ideone example
I need to forward some predefined arguments plus some user-passed arguments to a member function.
#define FWD(xs) ::std::forward<decltype(xs)>(xs)
template<class T, class... Ts, class... TArgs>
void forwarder(void(T::*fptr)(Ts...), TArgs&&... xs)
{
T instance;
(instance.*fptr)(FWD(xs)..., 0);
// ^
// example predefined argument
}
forwarder(&example::f0, 10, 'a');
forwarder(&example::f1, 10, "hello", 5);
This works properly for non-template member functions.
The member function pointer passed to forwarder can, however, point to template functions as well. Unfortunately, the compiler is not able to deduce the type of T in that case:
struct example
{
void f0(int, int) { }
template<class T>
void f1(T&&, int) { }
};
// Compiles
forwarder(&example::f0, 10);
// Does not compile
forwarder(&example::f1, 10);
Errors:
prog.cpp:30:28: error: no matching function for call to 'forwarder(<unresolved overloaded function type>, int)'
forwarder(&example::f1, 10);
^
prog.cpp:20:6: note: candidate: template<class T, class ... Ts, class ... TArgs> void forwarder(void (T::*)(Ts ...), TArgs&& ...)
void forwarder(void(T::*fptr)(Ts...), TArgs&&... xs)
^
prog.cpp:20:6: note: template argument deduction/substitution failed:
prog.cpp:30:28: note: couldn't deduce template parameter 'T'
forwarder(&example::f1, 10);
Is there any way I can help the compiler deduce the correct types without changing the interface of forwarder?
If not, what's the best way of solving this issue without making the user syntax too convoluted?
EDIT: It would also be acceptable to pass the member function pointer as a template parameter, maybe through a wrapper. The target member function will always be known at compile-time. Pseudocode:
forwarder<WRAP<example::f0>>(10, 'a');
// Where WRAP can be a macro or a type alias.
ideone example
I compiled your code in gcc 4.9 by providing template arguments to the member function pointer;
like this
int main(){
// Compiles
forwarder(&example::f0, 10);
//Does not compile
forwarder(&example::f1, 10);
//Does compile, instantiate template with int or what ever you need
forwarder(&example::f1<int>,10)
}
I believe what is going on is that you need to instantiate the template member function.
does that change your interface too much?
I think any answer will revolve around instantiating that member template somehow.
Related
I have a function template as in the following minimal snippet. I want to test if it is callable before making the call:
#include <concepts>
void f(auto a) {}
// void f(int a) {} // This is ok
static_assert(std::invocable<decltype(f), int>);
But it does not compile with error
error: 'decltype' cannot resolve address of overloaded function
Alternatively,
void f(auto a) {}
template <auto F> concept callable = requires { {F(27)}; };
static_assert(callable<f>);
gives error
error: unable to deduce 'auto' from 'f'
Is this a limitation of C++20 language? Is there any way to force an instantiation of f<int>? Are there alternatives to make the check compile without changes to f?
A function template can only perform template argument deduction if you call it. So if you're not calling it, the only things you can do with a function template name is give it the template parameters you want (thus resolving into an actual function).
I want to pass a callable (std::function object) into a class Foo. The callable refers to a member method of another class which has arbitrary arguments, hence the Foo must be a variadic template. Consider this code:
struct Bar {
void MemberFunction(int x) {}
};
template<typename ...Args>
class Foo {
public:
Foo(std::function<void(Bar*, Args...)> f) {}
};
int main() {
Foo<int> m1(&Bar::MemberFunction);
return 0;
}
This compiles fine. Now I want to write a factory function MakeFoo() which returns a unique_ptr to a Foo object:
template<typename ...Args>
std::unique_ptr<Foo<Args...>> MakeFoo(std::function<void(Bar*, Args...)> f) {
return std::make_unique<Foo<Args...>>(f);
}
Using this function by calling
auto m2 = MakeFoo<int>(&Bar::MemberFunction);
in main, gives me the following compiler errors:
functional.cc: In function ‘int main()’:
functional.cc:21:50: error: no matching function for call to ‘MakeFoo(void (Bar::*)(int))’
auto m2 = MakeFoo<int>(&Bar::MemberFunction);
^
functional.cc:15:35: note: candidate: template<class ... Args> std::unique_ptr<Foo<Args ...> > MakeFoo(std::function<void(Bar*, Args ...)>)
std::unique_ptr<Foo<Args...>> MakeFoo(std::function<void(Bar*, Args...)> f) {
^
functional.cc:15:35: note: template argument deduction/substitution failed:
functional.cc:21:50: note: mismatched types ‘std::function<void(Bar*, Args ...)>’ and ‘void (Bar::*)(int)’
auto m2 = MakeFoo<int>(&Bar::MemberFunction);
It seems to me, that when I call the constructor of Foo, the compiler happily converts the function pointer &Bar::MemberFunction to a std::function object. But when I pass the same argument to the factory function, it complains. Moreover, this problem only seems to occur, when Foo and MakeFoo are variadic templates. For a fixed number of template parameters it works fine.
Can somebody explain this to me?
Why doesn't it work without explicit <int>?
Prior to C++17, template type deduction is pure pattern matching.
std::function<void(Foo*)> can store a member function pointer of type void(Foo::*)(), but a void(Foo::*)() is not a std::function of any kind.
MakeFoo takes its argument, and pattern matches std::function<void(Bar*, Args...)>. As its argument is not a std::function, this pattern matching fails.
In your other case, you had fixed Args..., and all it had to do was convert to a std::function<void(Bar*, Args...)>. And there is no problem.
What can be converted to is different than what can be deduced. There are a myriad of types of std::function a given member function could be converted to. For example:
struct Foo {
void set( double );
};
std::function< void(Foo*, int) > hello = &Foo::set;
std::function< void(Foo*, double) > or_this = &Foo::set;
std::function< void(Foo*, char) > why_not_this = &Foo::set;
In this case there is ambiguity; in the general case, the set of template arguments that could be used to construct some arbitrary template type from an argument requires inverting a turing-complete computation, which involves solving Halt.
Now, C++17 added deduction guides. They permit:
std::function f = &Foo::set;
and f deduces the signature for you.
In C++17, deduction doesn't guides don't kick in here; they may elsewhere, or later on.
Why doesn't it work with explicit <int>?
Because it still tries to pattern match and determine what the rest of Args... are.
If you changed MakeFoo to
template<class T>
std::unique_ptr<Foo<T>> MakeFoo(std::function<void(Bar*, T)> f) {
return std::make_unique<Foo<T>>(f);
}
suddenly your code compiles. You pass it int, there is no deduction to do, and you win.
But when you have
template<class...Args>
std::unique_ptr<Foo<Args...>> MakeFoo(std::function<void(Bar*, Args...)> f) {
return std::make_unique<Foo<T>>(f);
}
the compiler sees <int> and says "ok, so Args... starts with int. What comes next?".
And it tries to pattern match.
And it fails.
How can you fix it?
template<class T>struct tag_t{using type=T; constexpr tag_t(){}};
template<class T>using block_deduction=typename tag_t<T>::type;
template<class...Args>
std::unique_ptr<Foo<Args...>> MakeFoo(
block_deduction<std::function<void(Bar*, Args...)>> f
) {
return std::make_unique<Foo<T>>(f);
}
now I have told the compiler not to deduce using the first argument.
With nothing to deduce, it is satisfied that Args... is just int, and... it now works.
The compiler cannot deduce the template arguments for std::function from a different type, such as member function pointer. Even though a std::function can be constructed from on object of that type, to consider the constructor the template arguments of std::function must be first known.
To help it deduce, add another overload:
template<typename ...Args>
std::unique_ptr<Foo<Args...>> MakeFoo(void(Bar::*f)(Args...)) {
return std::make_unique<Foo<Args...>>(f);
}
MakeFoo<int>( whatever );
is equivalent to invoking the hypothetical
template<typename ...Tail>
std::unique_ptr<Foo<int,Tail...>> MakeFoo( std::function<void(Bar*,int,Tail...)> f) {
return std::make_unique<Foo<int,Tail...>>(f);
}
clearly, in no way the compiler can deduce that Tail is empty given a void(Bar::*)(int)
IMO, the most correct fix ( given the required usage ) is to make the args non deduced:
template< typename T >
struct nondeduced { using type = T; };
template<typename ...Args>
std::unique_ptr<Foo<Args...>> MakeFoo( std::function<void(Bar*, typename nondeduced<Args>::type... )> f ) {
I'm experimenting with resolving the address of an overloaded function (bar) in the context of another function's parameter (foo1/foo2).
struct Baz {};
int bar() { return 0; }
float bar(int) { return 0.0f; }
void bar(Baz *) {}
void foo1(void (&)(Baz *)) {}
template <class T, class D>
auto foo2(D *d) -> void_t<decltype(d(std::declval<T*>()))> {}
int main() {
foo1(bar); // Works
foo2<Baz>(bar); // Fails
}
There's no trouble with foo1, which specifies bar's type explicitly.
However, foo2, which disable itself via SFINAE for all but one version of bar, fails to compile with the following message :
main.cpp:19:5: fatal error: no matching function for call to 'foo2'
foo2<Baz>(bar); // Fails
^~~~~~~~~
main.cpp:15:6: note: candidate template ignored: couldn't infer template argument 'D'
auto foo2(D *d) -> void_t<decltype(d(std::declval<T*>()))> {}
^
1 error generated.
It is my understanding that C++ cannot resolve the overloaded function's address and perform template argument deduction at the same time.
Is that the cause ? Is there a way to make foo2<Baz>(bar); (or something similar) compile ?
As mentioned in the comments, [14.8.2.1/6] (working draft, deducing template arguments from a function call) rules in this case (emphasis mine):
When P is a function type, function pointer type, or pointer to member function type:
If the argument is an overload set containing one or more function templates, the parameter is treated as a non-deduced context.
If the argument is an overload set (not containing function templates), trial argument deduction is attempted using each of the members of the set. If deduction succeeds for only one of the overload set members, that member is used as the argument value for the deduction. If deduction succeeds for more than one member of the overload set the parameter is treated as a non-deduced context.
SFINAE takes its part to the game once the deduction is over, so it doesn't help to work around the standard's rules.
For further details, you can see the examples at the end of the bullet linked above.
About your last question:
Is there a way to make foo2<Baz>(bar); (or something similar) compile ?
Two possible alternatives:
If you don't want to modify the definition of foo2, you can invoke it as:
foo2<Baz>(static_cast<void(*)(Baz *)>(bar));
This way you explicitly pick a function out of the overload set.
If modifying foo2 is allowed, you can rewrite it as:
template <class T, class R>
auto foo2(R(*d)(T*)) {}
It's more or less what you had before, no decltype in this case and a return type you can freely ignore.
Actually you don't need to use any SFINAE'd function to do that, deduction is enough.
In this case foo2<Baz>(bar); is correctly resolved.
Some kind of the general answer is here: Expression SFINAE to overload on type of passed function pointer
For the practical case, there's no need to use type traits or decltype() - the good old overload resolution will select the most appropriate function for you and break it into 'arguments' and 'return type'. Just enumerate all possible calling conventions
// Common functions
template <class T, typename R> void foo2(R(*)(T*)) {}
// Different calling conventions
#ifdef _W64
template <class T, typename R> void foo2(R(__vectorcall *)(T*)) {}
#else
template <class T, typename R> void foo2(R(__stdcall *)(T*)) {}
#endif
// Lambdas
template <class T, class D>
auto foo2(const D &d) -> void_t<decltype(d(std::declval<T*>()))> {}
It could be useful to wrap them in a templated structure
template<typename... T>
struct Foo2 {
// Common functions
template <typename R> static void foo2(R(*)(T*...)) {}
...
};
Zoo2<Baz>::foo2(bar);
Although, it will require more code for member functions as they have modifiers (const, volatile, &&)
Normally, to test a if a pointer points to function, use std::is_function is enough.
However, it cannot work with lambda. Since lambda is an object with operator().
Now I have to use both is_function and is_object to check if one works like function, as below:
std::is_function<decltype(f)>::value || std::is_object<decltype(f)>::value
So I'm wondering if there is a better way to test if one is lambda or not?
EDIT:
Related code:
template<typename Func>
void deferJob(Func f, int ms=2000)
{
if(! std::is_function<decltype(f)>::value
&& ! std::is_object<decltype(f)>::value){
qDebug()<<"Not function!";
return;
}
QTimer* t = new QTimer;
t->setSingleShot(true);
QObject::connect(t, &QTimer::timeout,
[&f, t](){
qDebug()<<"deferJob";
f();
t->deleteLater();
});
t->start(ms);
}
EDIT2:
Similar question: C++ metafunction to determine whether a type is callable
So here are some thoughts that may or may not be helpful.
To create a type_trait that works for functors, lambdas and traditional functions, I think I would look into seeing if the template argument is convertible into a std::function<void()>. I think that would cover most bases in a clear way.
As we've mentioned in the comments, you can't test a template argument like the way you are doing. The f() later in the function will cause a compile error, and so you'll never have the opportunity to see the runtime error.
You can try to do something with std::enable_if. You'd need to create template specializations so that SFINAE can function to choose the correct implementation. This would use that type_trait that I mentioned in bullet 1.
If you did this, you could make the implementation of the other template to be a static_assert to create a "better" error message.
That being said, the compiler error messages aren't that bad in the first place. (At least in clang and gcc. I haven't looked as msvc).
This doesn't get you a great error message, but it does get you a different one:
#include <cassert>
#include <functional>
#include <type_traits>
template <typename Func>
typename std::enable_if<std::is_convertible<Func, std::function<void()>>::value>::type
deferJob(Func f, int ms=2000) {
}
void normal_function() {}
int main() {
deferJob([]() {}); // works
deferJob(&normal_function); // works
deferJob(3); // compile time error
}
In Clang, I get an error that looks like:
foo.cc:15:2: error: no matching function for call to 'deferJob'
deferJob(3); // compile time error
^~~~~~~~
foo.cc:6:25: note: candidate template ignored: disabled by 'enable_if' [with Func = int]
typename std::enable_if<std::is_convertible<Func, std::function<void()>>::value>::type
In GCC, I get an error that looks like:
foo.cc: In function ‘int main()’:
foo.cc:15:12: error: no matching function for call to ‘deferJob(int)’
deferJob(3); // compile time error
^
foo.cc:15:12: note: candidate is:
foo.cc:7:1: note: template<class Func> typename std::enable_if<std::is_convertible<Func, std::function<void()> >::value>::type deferJob(Func, int)
deferJob(Func f, int ms=2000) {
^
foo.cc:7:1: note: template argument deduction/substitution failed:
foo.cc: In substitution of ‘template<class Func> typename std::enable_if<std::is_convertible<Func, std::function<void()> >::value>::type deferJob(Func, int) [with Func = int]’:
foo.cc:15:12: required from here
foo.cc:7:1: error: no type named ‘type’ in ‘struct std::enable_if<false, void>’
We could go one step further (although doing it this way makes it hard to extend further) and add an additional function:
template <typename Func>
typename std::enable_if<not std::is_convertible<Func, std::function<void()>>::value>::type
deferJob(Func f, int ms=2000) {
static_assert(false, "You should pass a function");
}
This causes clang to report (at compile time):
foo.cc: In function ‘typename std::enable_if<(! std::is_convertible<Func, std::function<void()> >::value)>::type deferJob(Func, int)’:
foo.cc:14:2: error: static assertion failed: You should pass a function
static_assert(false, "You should pass a function");
But sadly, it doesn't give a stack trace, so I would find this far less helpful than any of the earlier messages.
And finally, we could also replace that static assert with your runtime message:
template <typename Func>
typename std::enable_if<not std::is_convertible<Func, std::function<void()>>::value>::type
deferJob(Func f, int ms=2000) {
qDebug() << "Not function!";
}
I have a variadic template function f. This compiles fine (using g++ -std=c++11 and possibly using c++0x):
#include <tuple>
template<int ...>
struct seq { };
template <typename ...T, int ...S>
void f(std::tuple<T...> arg, seq<S...> s) {
// ... do stuff
}
int main() {
f<int>(std::tuple<int>(10), seq<0>());
return 0;
}
The compiler automatically fills in the int ...S that works.
However, I can't seem to manually provide the integer arguments:
int main() {
f<int, 0>(std::tuple<int>(10), seq<0>());
return 0;
}
Output:
/tmp/t.cpp: In function ‘int main()’: /tmp/t.cpp:12:42: error: no
matching function for call to ‘f(std::tuple, seq<0>)’
/tmp/t.cpp:12:42: note: candidate is: /tmp/t.cpp:7:6: note:
template void f(std::tuple<_TElements ...>,
seq) /tmp/t.cpp:7:6: note: template argument
deduction/substitution failed:
I believe I've read that technically there should only be one variadic template parameter pack provided to a template function (and in the first case, it is completely determined by context), so that explains it(?).
For debugging, is there a way in GCC to output the expansion used for ...S to stderr or stdout? It would be very useful for debugging things like this when they don't compile at first.
I know no way to specify two template argument packs manually. Since a template pack may contain arbitrarily many arguments, there is no way for the compiler to know when you meant the first one to stop and the second one to start. Automatic or partially automatic deduction seems to work, though, but I am not sure if this is just some generousity of g++...
I am not sure what you are actually trying to do, but I bet that you do not need both template packs at the same time. You might introduce one layer of indirection, e.g.,
template <typename ... Tuple_Elements>
void do_something_with_single_value(std::tuple<Tuple_Elements...> arg, int s) {
// ... do stuff
}
template <typename Tuple_Type, int ...S>
void f(Tuple_Type arg, seq<S...> s) {
// ... do stuff which needs all S at the same time
// ... call do_something_with_single_value in compile time loop to access tuple elements
}
Perhaps your signature is a hint that your function has too many responsibilities. Try to create smaller functions with clear responsibilities.
There is a way to output the arguments deduced for T and S, but only if the compiler can determine a match. For this, you would need to provoke an error at compile time:
template <typename ...T, int ...S>
void f(std::tuple<T...> arg, seq<S...> s) {
static_assert(std::tuple_size<std::tuple<T...>>::value < 0, "Provoked error message");
// ... do stuff
}
This would generate the following output in your working example:
stack.cpp: In function ‘void f(std::tuple<_Elements ...>, seq<S ...>) [with T = {int}, int ...S = {0}]’:
stack.cpp:15:34: instantiated from here
stack.cpp:10:2: error: static assertion failed: "Provoked error message"
For getting stderr for types and values in situations like this I, personally, find it best to force a compile error for the situation you're interested in.
So in this situation we want to know exactly what the type and integer packs for the first example where it compiles correctly. If we cause a compile fail before instantiation of the function then the compile error will refer to the function without the info we want:
template <class ... T, int ... S>
void f (std::tuple<T...> arg, seq<S...> s)
{
foo
}
In function 'void f(std::tuple<_Elements ...>, seq<S ...>)':
error: 'foo' was not declared in this scope
demo
So now let's fail compilation during instantiation. This means that we'll have to write something that could make sense for some types of T..., but not for our instantiation. I usually write a function like force_fail to make this easy to repeat:
template <class T, class ...>
int force_compile_fail ()
{
return T::force_compile_fail;
}
template <class ... T, int ... S>
void f (std::tuple<T...> arg, seq<S...> s)
{
force_compile_fail<T...>();
}
In instantiation of 'int force_compile_fail() [with T = int;
= {}]':
required from 'void f(std::tuple<_Elements ...>, seq<S ...>) [with T = {int}; int ...S = {0}]'
required from here
error: 'force_compile_fail' is not a member of 'int'
return T::force_compile_fail;
demo