I'm writing an Option class which represents a value that may or may not exist. The if_opt function is intended to take an Option and a function which will be called on the value held in the Option, but only if the value exists.
template <class T>
class Option {
private:
std::shared_ptr<T> m_value;
public:
explicit operator bool()const noexcept
{
return (bool)m_value;
}
Option() = default;
explicit Option(T value)
{
m_value = std::make_shared<T>(value);
}
template <class U>
friend void if_opt(Option<U>&, std::function<void(U&)>);
};
template <class T>
void if_opt(Option<T>& opt, std::function<void(T&)> f)
{
if (opt) f(*opt.m_value);
};
I've noticed that this works if I use it like so:
Option<int> none;
Option<int> some(10);
function<void(int&)> f1 = [](int& none)
{
cout << "This should never be reached" << endl;
};
function<void(int&)> f2 = [](int& some)
{
cout << "The value of some is: " << some << endl;
};
if_opt(none, f1);
if_opt(some, f2);
But I'd like to be able to put the lambda expression directly in the call, but when I do:
if_opt(none, [](int&)
{
cout << "This should never be reached" << endl;
});
if_opt(some, [](int& some)
{
cout << "The value of some is: " << some << endl;
});
I get an error:
error: no matching function for call to 'if_opt(Option<int>&, main()::<lambda(int&)>)'
I know that the type of a lambda expression is undefined in the standard, and that it merely has to be assignable to std::function<R(T)>, so this sort of makes sense, but is there a way that I can get the lambda argument to implicitly convert to a std::function<void(T&)> so that I can define the lambda in the call to if_opt the way I attempted?
std::function<Sig> is a type erasure tool. It erases (almost) everything about the value it stores excpet that it can be invoked with Sig.
Template argument deduction takes a passed in type and deduces what types should be used, then the template function is generated and (usually) called.
These are almost inverses of each other. Doing deduction on a type erasure template is code smell, and almost always a bad idea.
So that is your fundamental design error.
There are a number of ways to fix your code.
First, if_opt shouldn't be a template.
friend void if_opt(Option<T>& opt, std::function<void(T&)> f){
if (opt) f(*opt.m_value);
}
this creates what I call a Koenig friend. You have to define the body inline. Really, that U type is pointless, and can even lead to errors in some cases.
But the type erasure here is also pointless. Fixing that returns the template, but now for a good reason.
template<class F>
friend void if_opt(Option<T>& opt, F&& f){
if (opt) f(*opt.m_value);
}
this is a better design.
You can go and invest in SFINAE overload resolution code, but I wouldn't bother.
template<class F,
std::conditional_t<true, bool,std::result_of_t<F&(T&)>> = true
>
friend void if_opt(Option<T>& opt, F&& f){
if (opt) f(*opt.m_value);
}
the above is obscure and has minimal marginal advantages over the one above it.
Related
I have common code – Dijkstra's algorithm – I use in different contexts, so I decided to use tag dispatch.
The common code is in the following function (you can see End get dispatched depending on the Tag template parameter):
template <typename Tag, typename ... Args>
void Dijkstra(blahblah, Args&&... arg) {
...
if (End(Tag(), cost, n_id, distances, time_limit, args ...)) {
break;
}
For most of the contexts I define a default no-op as follows:
template<typename ... Args>
bool inline End(Args&& ...) {
return false;
}
For one context I define the function with the following signature:
bool inline End(OneContextTag, Duration d, NodeId n_id, Distances distances, Du time_limit, blahblah) {
Everything worked as expected, till I found I forgot & in the signature after Distances – I was copying Distances, a large unordered_map, every time.
However, after I changed it to const Distances& to avoid expensive copying, the less specialized noop version got called. I have no idea why. And how to fix it.
(I swear the change is only in adding a single character &. Or const&)
(The signature is otherwise correct, if I comment out the generic noop version, it just uses the OneContextTag version.)
(The code is more complex, but I hope it can be figured out from this.)
So what you're asking about is basically why the following program prints Special foo but Generic bar:
struct A {};
template<class ... Args>
void foo(Args&&...)
{
std::cout << "Generic foo\n";
}
void foo(A)
{
std::cout << "Special foo\n";
}
template<class ... Args>
void bar(Args&&...)
{
std::cout << "Generic bar\n";
}
void bar(A const&)
{
std::cout << "Special bar\n";
}
int main()
{
A a;
foo(a);
bar(a);
}
Let's look at what happens for overload resolution:
1. Candidate functions are selected.
C++11/[over.match.funcs]/7 In each case where a candidate is a function template, candidate function template specializations are generated using template argument deduction (14.8.3, 14.8.2). Those candidates are then handled as candidate functions in the usual way.
Candidates for call to foo(a):
template<> void foo<A&>(A&); // reference collapsing
void foo(A);
Candidates for call to bar(a):
template<> void bar<A&>(A&);
void bar(A const&);
2. Select of best viable function:
In the first place, an overload is better if (at least) one of the parameters has a better conversion sequence (and no other has a worse conversion sequence).
C++11/[over.ics.rank]/3 Standard conversion sequence S1 is a better conversion sequence than standard conversion sequence S2 if [ ... ] S1 and S2 are reference bindings (8.5.3), and the types to which the references refer are the same type except for top-level cv-qualifiers, and the type to which the reference initialized by S2 refers is more cv-qualified than the type to which the reference initialized by S1 refers.
This results in the preference of the template candidate for bar since the conversion required to call void bar(A const&) requires binding an lvalue to an more cv-qualified const lvalue reference.
Therefore, you see the generic version called when using Distances const&.
C++11/[over.best.ics]/6 When the parameter type is not a reference [ ... ]
When the parameter has a class type and the argument expression has the same type, the implicit conversion sequence is an identity conversion.
This makes the conversion sequence for the parameter a when passed to void foo(A) an identity conversion (which is also the case for the template function).
If neither of the overloads has a better conversion sequence, then the non-template version wins over the template.
C++11/[over.match.best]/1 [ ... ] Given these definitions, a viable function F1 is defined to be a better function than another viable function F2 if [ ... ] F1 is a non-template function and F2 is a function template specialization.
This is the case for foo and makes your code behave as you intended when you use Distances distances.
I do not have an answer to why overload resolution works the way it does here atm. But I have a potential solution for you, which is also (IMO) more robust:
Change the default End to accept a UseDefaultEnd tag as the first parameter. For each context which should use the default End, subclass its tag from UseDefaultEnd:
#include <iostream>
struct UseDefaultEnd {};
/* Comment first parameter; then you get the same behavior as
you're currently trying to solve. */
template<typename ... Args>
bool inline End(UseDefaultEnd, Args&& ...) {
// bool inline End(Args&& ...) {
return false;
}
struct OneTag {};
struct OtherTag : public UseDefaultEnd {};
bool inline End(OneTag, int const & i) {
return true;
}
template<typename Tag>
void Caller() {
int i = 42;
if (End(Tag(), i)) {
std::cout << "Used specific version of End" << std::endl;
}
}
int main() {
Caller<OtherTag>();
std::cout << "---" << std::endl;
Caller<OneTag>();
}
Suppose you have the following pair of functions:
void f(const int&) {
// Do something, making a copy of the argument.
}
void f(int&&) {
// Do the same thing, but moving the argument.
}
They are fairly redundant—the only difference between the functions being whether they copy or move their argument. Of course, we can do better by re-writing this as a single template function:
template<typename T>
void g(T&&) {
// Do something, possibly using std::forward to copy or move the argument.
}
This works, and is a commonly used idiom in practice. But the template might be instantiated into three functions, up from our two above. We can verify this occurs with the following piece of code:
#include <iostream>
template<typename T> constexpr char *type = nullptr;
template<> constexpr const char *type<int&> = "int&";
template<> constexpr const char *type<const int&> = "const int&";
template<> constexpr const char *type<int> = "int";
template<typename T>
void g(T&&) {
std::cout << reinterpret_cast<void*>(&g<T>)
<< " = &g<" << type<T> << ">" << std::endl;
}
int main() {
int i = 0;
const int& cr = 0;
g(i);
g(cr);
g(0);
return 0;
}
/*
Prints:
0x100f45080 = &g<int&>
0x100f45100 = &g<const int&>
0x100f45180 = &g<int>
*/
This has added a third function for the case when T = int&, which we didn't have when we were using our non-templated function f above. In this case, we don't actually need this non-const l-value reference version of the function—given f was sufficient for our original needs—and this increases the size of our code, especially if we have many template functions written this way that call each other.
Is there a way to write our function g above so that the compiler will automatically deduce T = const int& when g(i) is called in our example code? I.e., a way where we don't have to manually write g<const int&>(i) yet still get the desired behavior.
It is a subjective point-of-view to say "forward references" ("universal references") are better than dedicated overloads. There are certainly many cases where this is true, but if you want to have full control they won't do all the jobs.
You could explicitly make sure users do not pass non-const lvalue references, by adding
static_assert(!std::is_lvalue_reference<T>::value || std::is_const<typename std::remove_reference<T>::type>::value, "only call g with const argument");
inside g, but this is not in all cases a very good solution.
Or you do what is done for vector::push_back(...) and provide explicit overloads -- but this was your starting point, see https://en.cppreference.com/w/cpp/container/vector/push_back.
The 'correct' answer just depends on your requirements.
Edit:
the suggestion of #Sjoerd would look something like:
template <typename T>
class aBitComplicated {
public:
void func(T&& v) { internal_func(std::forward<T>(v)); }
void func(const T& v) { internal_func(v); }
private:
template <typename U>
void internal_func(U&& v) { /* your universal code*/ }
};
There also a bit more sophisticated/complicated version of this, but this here should be the most simple version to achieve what you asked for.
I'm trying to programming in C++ a framework where the user can indicates a set of functions inside its program where he wants to apply a memoization strategy.
So let's suppose that we have 5 functions in our program f1...f5 and we want to avoid the (expensive) re-computation for the functions f1 and f3 if we already called them with the same input. Notice that each function can have different return and argument types.
I found this solution for the problem, but you can use only double and int.
MY SOLUTION
Ok I wrote this solution for my problem, but I don't know if it's efficient, typesafe or can be written in any more elegant way.
template <typename ReturnType, typename... Args>
function<ReturnType(Args...)> memoize(function<ReturnType(Args...)> func)
{
return ([=](Args... args) mutable {
static map<tuple<Args...>, ReturnType> cache;
tuple<Args...> t(args...);
auto result = cache.insert(make_pair(t, ReturnType{}));
if (result.second) {
// insertion succeeded so the value wasn't cached already
result.first->second = func(args...);
}
return result.first->second;
});
}
struct MultiMemoizator
{
map<string, boost::any> multiCache;
template <typename ReturnType, typename... Args>
void addFunction(string name, function < ReturnType(Args...)> func) {
function < ReturnType(Args...)> cachedFunc = memoize(func);
boost::any anyCachedFunc = cachedFunc;
auto result = multiCache.insert(pair<string, boost::any>(name,anyCachedFunc));
if (!result.second)
cout << "ERROR: key " + name + " was already inserted" << endl;
}
template <typename ReturnType, typename... Args>
ReturnType callFunction(string name, Args... args) {
auto it = multiCache.find(name);
if (it == multiCache.end())
throw KeyNotFound(name);
boost::any anyCachedFunc = it->second;
function < ReturnType(Args...)> cachedFunc = boost::any_cast<function<ReturnType(Args...)>> (anyCachedFunc);
return cachedFunc(args...);
}
};
And this is a possible main:
int main()
{
function<int(int)> intFun = [](int i) {return ++i; };
function<string(string)> stringFun = [](string s) {
return "Hello "+s;
};
MultiMemoizator mem;
mem.addFunction("intFun",intFun);
mem.addFunction("stringFun", stringFun);
try
{
cout << mem.callFunction<int, int>("intFun", 1)<<endl;//print 2
cout << mem.callFunction<string, string>("stringFun", " World!") << endl;//print Hello World!
cout << mem.callFunction<string, string>("TrumpIsADickHead", " World!") << endl;//KeyNotFound thrown
}
catch (boost::bad_any_cast e)
{
cout << "Bad function calling: "<<e.what()<<endl;
return 1;
}
catch (KeyNotFound e)
{
cout << e.what()<<endl;
return 1;
}
}
How about something like this:
template <typename result_t, typename... args_t>
class Memoizer
{
public:
typedef result_t (*function_t)(args_t...);
Memoizer(function_t func) : m_func(func) {}
result_t operator() (args_t... args)
{
auto args_tuple = make_tuple(args...);
auto it = m_results.find(args_tuple);
if (it != m_results.end())
return it->second;
result_t result = m_func(args...);
m_results.insert(make_pair(args_tuple, result));
return result;
}
protected:
function_t m_func;
map<tuple<args_t...>, result_t> m_results;
};
Usage is like this:
// could create make_memoizer like make_tuple to eliminate the template arguments
Memoizer<double, double> memo(fabs);
cout << memo(-123.456);
cout << memo(-123.456); // not recomputed
It's pretty hard to guess at how you're planning to use the functions, with or without memoisation, but for the container-of-various-function<>s aspect you just need a common base class:
#include <iostream>
#include <vector>
#include <functional>
struct Any_Function
{
virtual ~Any_Function() {}
};
template <typename Ret, typename... Args>
struct Function : Any_Function, std::function<Ret(Args...)>
{
template <typename T>
Function(T& f)
: std::function<Ret(Args...)>(f)
{ }
};
int main()
{
std::vector<Any_Function*> fun_vect;
auto* p = new Function<int, double, double, int> { [](double i, double j, int z) {
return int(i + j + z);
} };
fun_vect.push_back(p);
}
The problem with this is how to make it type-safe. Look at this code:
MultiMemoizator mm;
std::string name = "identity";
mm.addFunction(name, identity);
auto result = mm.callFunction(name, 1);
Is the last line correct? Does callFunction have the right number of parameters with the right types? And what is the return type?
The compiler has no way to know that: it has no way of understanding that name is "identity" and even if it did, no way to associate that with the type of the function. And this is not specific to C++, any statically-typed language is going to have the same problem.
One solution (which is basically the one given in Tony D's answer) is to tell the compiler the function signature when you call the function. And if you say it wrong, a runtime error occurs. That could look something like this (you only need to explicitly specify the return type, since the number and type of parameters is inferred):
auto result = mm.callFunction<int>(name, 1);
But this is inelegant and error-prone.
Depending on your exact requirements, what might work better is to use "smart" keys, instead of strings: the key has the function signature embedded in its type, so you don't have to worry about specifying it correctly. That could look something like:
Key<int(int)> identityKey;
mm.addFunction(identityKey, identity);
auto result = mm.callFunction(identityKey, 1);
This way, the types are checked at compile time (both for addFunction and callFunction), which should give you exactly what you want.
I haven't actually implemented this in C++, but I don't see any reason why it should be hard or impossible. Especially since doing something very similar in C# is simple.
you can use vector of functions with signature like void someFunction(void *r, ...) where r is a pointer to result and ... is variadic argument list. Warning: unpacking argument list is really inconvenient and looks more like a hack.
At first glance, how about defining a type that has template arguments that differ for each function, i.e.:
template <class RetType, class ArgType>
class AbstractFunction {
//etc.
}
have the AbstractFunction take a function pointer to the functions f1-f5 with template specializations different for each function. You can then have a generic run_memoized() function, either as a member function of AbstractFunction or a templated function that takes an AbstractFunction as an argument and maintains a memo as it runs it.
The hardest part will be if the functions f1-f5 have more than one argument, in which case you'll need to do some funky things with arglists as template parameters but I think C++14 has some features that might make this possible. An alternative is to rewrite f1-f5 so that they all take a single struct as an argument rather than multiple arguments.
EDIT: Having seen your problem 1, the problem you're running into is that you want to have a data structure whose values are memoized functions, each of which could have different arguments.
I, personally, would solve this just by making the data structure use void* to represent the individual memoized functions, and then in the callFunction() method use an unsafe type cast from void* to the templated MemoizedFunction type you need (you may need to allocate MemoizedFunctions with the "new" operator so that you can convert them to and from void*s.)
If the lack of type safety here irks you, good for you, in that case it may be a reasonable option just to make hand-written helper methods for each of f1-f5 and have callFunction() dispatch one of those functions based on the input string. This will let you use compile-time type checking.
EDIT #2: If you are going to use this approach, you need to change the API for callFunction() slightly so that callFunction has template args matching the return and argument types of the function, for example:
int result = callFunction<int, arglist(double, float)>("double_and_float_to_int", 3.5, 4);
and if the user of this API ever types the argument type or return types incorrectly when using callFunction... pray for their soul because things will explode in very ugly ways.
EDIT #3: You can to some extent do the type checking you need at runtime using std::type_info and storing the typeid() of the argument type and return type in your MemoizedFunction so that you can check whether the template arguments in callFunction() are correct before calling - so you can prevent the explosion above. But this will add a bit of overhead every time you call the function (you could wrap this in a IF_DEBUG_MODE macro to only add this overhead during testing and not in production.)
So in the past few weeks, I've been experimenting with functional-programming type solutions to problems in C++11, and from time to time, I've been in a situation where I need a function that returns a constant value.
In Haskell, there is a function
const :: a -> b -> a
const x = \_ -> x
that returns a function that evaluates to const's original argument, no matter what argument is supplied to it. I would like to create something similar in C++11. Such constructions are useful for signifying special behavior in functions (a constant function of true sent to a filter would leave the data intact). Here's my first attempt:
template<class T>
std::function<T(...)> constF(T x) {
return ([x](...) { return x; });
}
This compiles on its own, but any attempt to use it results in incomplete-type errors. My second attempt was this:
template<class T, class... Args>
std::function<T(Args...)> constF(T x) {
return ([x](Args...) { return x; });
}
This comes closer, but doesn't allow me to supply any arguments, unless I explicitly state them.
auto trueFunc1 = constF(true);
auto trueFunc2 = constF<bool, int>(true);
cout << trueFunc1() << endl; //works
cout << trueFunc1(12) << endl; //doesn't compile
cout << trueFunc2(12) << endl; //works
Ideally, a correct construction would produce no difference between trueFunc1 and trueFunc2.
Is this even possible in C++?
Since C++11 doesn't have generic or variadic lambdas, I'd write a functor template class:
template <typename T>
// requires CopyConstructible<T>
class const_function {
T value;
public:
template <typename U, typename = typename std::enable_if<std::is_convertible<U,T>::value>::type>
const_function(U&& val) :
value(std::forward<U>(val)) {}
template <typename... Args>
T operator () (Args&&...) const {
return value;
}
};
and a nice type-deducing wrapper to make them:
template <typename T>
const_function<typename std::remove_reference<T>::type>
constF(T&& t) {
return {std::forward<T>(t)};
}
In C++1y, I think the simple equivalent is:
template <typename T>
auto constF(T&& t) {
return [t{std::forward<T>(t)}](auto&&...){return t;};
}
I have a boost::variant and I would like to execute a functor only if the variant is of a special type, so I made up this function:
template<typename T, typename Variant>
void if_init(Variant& opt_variant, std::function<void(T)> functor){
if(auto* ptr = boost::get<T>(&opt_variant)){
functor(*ptr);
}
}
This works well, but I would like the type T to be deduced, so that I can write that:
if_init(b, [](double var){ std::cout << "I'm double and set" << std::endl; });
But the type is not deduced:
type_inference.cpp:19:5: error: no matching function for call to 'if_init'
if_init(b, [](double var){ std::cout << "I'm double and set" << std::endl; });
^~~~~~~
type_inference.cpp:10:6: note: candidate template ignored: failed template argument deduction
void if_init(Variant& opt_variant, std::function<void(T)> functor){
If I write:
if_init<double>(b, [](double var){ std::cout << "I'm double and set" << std::endl; });
it works well.
Is there a way to have type T being deduced ? I would like to type T only once. Here the type is short, but in the real case, there are long types.
I'm using CLang 3.2.
Here is the full test case (the first call compiles not the second):
#include <iostream>
#include <functional>
#include <boost/variant.hpp>
typedef boost::variant<int, double> Test;
template<typename T, typename Variant>
void if_init(Variant& opt_variant, std::function<void(T)> functor){
if(auto* ptr = boost::get<T>(&opt_variant)){
functor(*ptr);
}
}
int main(){
Test b = 1.44;
if_init<double>(b, [](double var){ std::cout << "I'm double and set" << std::endl; });
if_init(b, [](int var){ std::cout << "I'm int and set" << std::endl; });
return 0;
}
I recommend you think of std::function<Sig> as a container of any one functor that conforms to Sig as a signature -- and which can be replaced at any moment. This functionality comes in very handy for e.g. std::vector<std::function<Sig>> because such a container can then hold functors of different types.
In your case, because you only care to have just the one functor you really don't need the functionality of std::function<Sig>. As such, I recommend you declare your function template like so:
template<typename T, typename Variant, typename Functor>
void if_init(Variant& opt_variant, Functor functor);
If you are worried that this doesn't communicate that Functor must conform to a void(T) signature, please note that std::function<Sig> does not enforce that either: although obviously you will end up with a compilation error, it is not a nice one. It's planned to be changed (and maybe your implementation has that either), but changed to a different kind of error. Still not that helpful for your case.
I personally make use of template aliases (in the template parameter list) to both document and enforce what a functor should conform to. This ends up looking like:
// Documents that e.g. long l = std::forward<Functor>(functor)(42.)
// should be a valid expression -- a functor that returns int would
// also be accepted.
// Triggers a hard-error (typically a static_assert with a nice message)
// on violation.
template<typename Functor, Requires<is_callable<Functor, long(double)>>...>
R foo(Functor functor);
// Documents that this function template only participates in overload resolution
// if the functor conforms to the signature.
// Does not trigger a hard-error (necessary by design); if everything goes right
// then another overload should be picked up -- otherwise an error of the kind
// 'no matching overload found' is produced
template<typename Functor, EnableIf<is_callable<Functor, long(double)>>...>
R bar(Functor functor);
As to your exact question, the rules of C++ do not allow for a template parameter to be deduced in your case. It's really not an easily fixed 'problem', if it is one. You can find more information on this.