"no matching function for call to" when having a function pointer with template arguments as a template argument - c++

I'm writing a template wrapper function that can be applied to a functions with different number/types of arguments.
I have some code that works but I'm trying to change more arguments into template parameters.
The working code:
#include <iostream>
int func0(bool b) { return b ? 1 : 2; }
//There is a few more funcX...
template<typename ...ARGS>
int wrapper(int (*func)(ARGS...), ARGS... args) { return (*func)(args...) * 10; }
int wrappedFunc0(bool b) { return wrapper<bool>(func0, b); }
int main()
{
std::cout << wrappedFunc0(true) << std::endl;
return 0;
}
Now I want int (*func)(ARGS...) to also be a template parameter. (It's for performance reasons. I want the pointer to be backed into the wrapper, because the way I'm using it prevents the compiler from optimizing it out.)
Here is what I came up with (The only difference is I've changed the one argument into a template parameter.):
#include <iostream>
int func0(bool b) { return b ? 1 : 2; }
//There is a few more funcX...
template<typename ...ARGS, int (*FUNC)(ARGS...)>
int wrapper(ARGS... args) { return (*FUNC)(args...) * 10; }
int wrappedFunc0(bool b) { return wrapper<bool, func0>(b); }
int main()
{
std::cout << wrappedFunc0(true) << std::endl;
return 0;
}
This doesn't compile. It shows:
<source>: In function 'int wrappedFunc0(bool)':
<source>:9:55: error: no matching function for call to 'wrapper<bool, func0>(bool&)'
9 | int wrappedFunc0(bool b) { return wrapper<bool, func0>(b); }
| ~~~~~~~~~~~~~~~~~~~~^~~
<source>:7:5: note: candidate: 'template<class ... ARGS, int (* FUNC)(ARGS ...)> int wrapper(ARGS ...)'
7 | int wrapper(ARGS... args) { return (*FUNC)(args...) * 10; }
| ^~~~~~~
<source>:7:5: note: template argument deduction/substitution failed:
<source>:9:55: error: type/value mismatch at argument 1 in template parameter list for 'template<class ... ARGS, int (* FUNC)(ARGS ...)> int wrapper(ARGS ...)'
9 | int wrappedFunc0(bool b) { return wrapper<bool, func0>(b); }
| ~~~~~~~~~~~~~~~~~~~~^~~
<source>:9:55: note: expected a type, got 'func0'
ASM generation compiler returned: 1
<source>: In function 'int wrappedFunc0(bool)':
<source>:9:55: error: no matching function for call to 'wrapper<bool, func0>(bool&)'
9 | int wrappedFunc0(bool b) { return wrapper<bool, func0>(b); }
| ~~~~~~~~~~~~~~~~~~~~^~~
<source>:7:5: note: candidate: 'template<class ... ARGS, int (* FUNC)(ARGS ...)> int wrapper(ARGS ...)'
7 | int wrapper(ARGS... args) { return (*FUNC)(args...) * 10; }
| ^~~~~~~
<source>:7:5: note: template argument deduction/substitution failed:
<source>:9:55: error: type/value mismatch at argument 1 in template parameter list for 'template<class ... ARGS, int (* FUNC)(ARGS ...)> int wrapper(ARGS ...)'
9 | int wrappedFunc0(bool b) { return wrapper<bool, func0>(b); }
| ~~~~~~~~~~~~~~~~~~~~^~~
<source>:9:55: note: expected a type, got 'func0'
Execution build compiler returned: 1
(link to the compiler explorer)
It looks like a problem with the compiler to me, but GCC and Clang agree on it so maybe it isn't.
Anyway, how can I make this template compile correctly with templated pointer to a function?
EDIT:
Addressing the duplicate flag Compilation issue with instantiating function template
I think the core of the problem in that question is the same as in mine, however, it lacks a solution that allows passing the pointer to function (not only its type) as a template parameter.

This doesn't work because a pack parameter (the one including ...) consumes all remaining arguments. All arguments following it can't be specified explicitly and must be deduced.
Normally you write such wrappers like this:
template <typename F, typename ...P>
int wrapper(F &&func, P &&... params)
{
return std::forward<F>(func)(std::forward<P>(params)...) * 10;
}
(And if the function is called more than once inside of the wrapper, all calls except the last can't use std::forward.)
This will pass the function by reference, which should be exactly the same as using a function pointer, but I have no reasons to believe that it would stop the compiler from optimizing it.
You can force the function to be encoded in the template argument by passing std::integral_constant<decltype(&func0), func0>{} instead of func0, but again, I don't think it's going to change anything.

The 2nd snippet is not valid because:
a type parameter pack cannot be expanded in its own parameter clause.
As from [temp.param]/17:
If a template-parameter is a type-parameter with an ellipsis prior to its optional identifier or is a parameter-declaration that declares a pack ([dcl.fct]), then the template-parameter is a template parameter pack. A template parameter pack that is a parameter-declaration whose type contains one or more unexpanded packs is a pack expansion. ... A template parameter pack that is a pack expansion shall not expand a template parameter pack declared in the same template-parameter-list.
So consider the following invalid example:
template<typename... Ts, Ts... vals> struct mytuple {}; //invalid
The above example is invalid because the template type parameter pack Ts cannot be expanded in its own parameter list.
For the same reason, your code example is invalid. For example, a simplified version of your 2nd snippet doesn't compile in msvc.

Related

Tagged structures casting rules

I was playing around with toy tuple implementations and eventually stuck with how get function works.
Consider this simple example
#include <iostream>
#include <utility>
template <size_t Tag, typename ValueType>
struct TagedValue { ValueType value; };
struct Test : TagedValue<0, int>, TagedValue<1, std::string>, TagedValue<2, double> {};
template <size_t Idx, typename T>
auto& get(Test& test) {
((TagedValue<Idx, T>&)(test)).value;
}
template <size_t Idx, typename T>
auto& get_impl(TagedValue<Idx, T>& tagged_value) {
return tagged_value.value;
}
template <size_t Idx>
auto& get_2(Test& test) {
return get_impl<Idx>(test);
}
int main()
{
Test test;
get_2<0>(test);
get<0>(test);
}
I get this error:
<source>: In function 'int main()':
<source>:29:16: error: no matching function for call to 'get<0>(Test&)'
29 | get<0>(test);
| ^
<source>:10:7: note: candidate: 'template<long unsigned int Idx, class T> auto& get(Test&)'
10 | auto& get(Test& test) {
| ^~~
<source>:10:7: note: template argument deduction/substitution failed:
<source>:29:16: note: couldn't deduce template parameter 'T'
29 | get<0>(test);
| ^
I do have couple of questions:
Basically why get_2 works and get doesn't compile. To me it looks like get_2 does exactly what I'm trying to do inside get
Does deducing T for get_2 take O(1) time, if yes how is it possible? Does compiler store some kind of map internally?
When you call a function template then all template arguments must either be specified explicitly or be deduced from the function arguments. When you call
get<0>(test);
Then Idx is 0, but there is no way for the compiler to know what T is supposed to be. The parameter is just Test, and T cannot be deduced from that.

Why can't this parameter pack accept function pointers?

I'm trying to create a parameter pack full of function pointers, but GCC (with c++17 standard) generates a deduction failed error. Why is that?
As written here:
For pointers to functions, the valid arguments are pointers to functions with linkage (or constant expressions that evaluate to null pointer values).
In my example, that's the case (isn't it?).
Is this rule invalidated for parameter packs? Did I miss something in the standard? If that's the case, how can I fix my code, without passing the function pointers as function arguments (ie without declaring T run2(T input, Funcs... funcs).
// In f.hpp
template<typename T>
T run2(T input)
{
return input;
}
template<typename T, T(*f)(T), class ... Funcs>
T run2(T input)
{
return run2<T, Funcs...>(f(input));
}
// In m.cpp
unsigned add2(unsigned v)
{
return v+2;
}
int main()
{
unsigned a=1;
a = run2<unsigned, add2>(a); // works
a = run2<unsigned, add2, add2>(a); // doesn't work
std::cout << a << std::endl;
return 0;
}
This the error I get with run2<unsigned, add2, add2> (GCC doesn't tell me why the last attempt actually failed):
m.cpp: In function ‘int main()’:
m.cpp:37:37: error: no matching function for call to ‘run2(unsigned int&)’
a = run2<unsigned, add2, add2>(a);
^
In file included from m.cpp:2:0:
./f.hpp:85:3: note: candidate: template<class T> T run2(T)
T run2(T input)
^
./f.hpp:85:3: note: template argument deduction/substitution failed:
m.cpp:37:37: error: wrong number of template arguments (3, should be 1)
a = run2<unsigned, add2, add2>(a);
^
In file included from m.cpp:2:0:
./f.hpp:109:3: note: candidate: template<class T, T (* f)(T), class ... Funcs> T run2(T)
T run2(T input)
^
./f.hpp:109:3: note: template argument deduction/substitution failed:
You declared a type parameter pack, class... Funcs. You can't pass function pointers as arguments for type parameters, because they are values, not types. Instead, you need to declare the run2 template so that it has a function pointer template parameter pack. The syntax to do so is as follows:
template<typename T, T(*f)(T), T(*...fs)(T)>
T run2(T input)
{
return run2<T, fs...>(f(input));
}
(The rule is that the ... is part of the declarator-id and goes right before the identifier, namely fs.)
The pack fs can accept one or more function pointers of type T (*)(T).

Why couldn't deduce const& template parameter?

Consider this code:
constexpr int TEN = 10;
template < const int& >
struct Object { };
template < const int& II >
void test(Object<II>) { }
Then the calls:
test<TEN>(Object<TEN>{}); // passes
test(Object<TEN>{}); // FAILS
The second call fails to compile with error message:
error: no matching function for call to ‘test(Object<TEN>)
note: candidate: template<const int& II> void test(Object<II>)
note: template argument deduction/substitution failed:
note: couldn't deduce template parameter ‘II’
The question is why? Is it according to the standard?
And the more important question is: how can I workaround this? That is: how can I help the compiler to deduce the const int& template parameter?
In the real code instead of int I have more complex literal type, so I do need the const&. Thus I can't just "use int instead of const int&".
I am using gcc-7.0.1 (the snapshot) and I am getting the same error with options -std=c++11, -std=c++14, -std=c++17.

deduce of argument of type class method (overloads by const qualifier) fails with trailing return type in gcc, but not in clang

Nothing clearer than an old good MCVE:
struct X {
auto get(int) const -> int { return {}; }
auto get(int) -> int { return {}; }
};
template <class R> auto f(auto (X::*)(int) const -> R) {}
// ^~~~ ~~~~
// trailing return type
int main() {
f(&X::get);
}
This fails in g++ (4.9.2 & 5.1.0). However if the old return type is used:
template <class R> auto f(R (X::*)(int) const) {}
// ^
// old return type
it works.
On clang (3.5.0) both variants work.
I know that trailing return type changes when the return type is inferred and the scope of it, so I wouldn't be quick to cast it as a gcc bug. So what does the standard says? Which compiler is right?
The most significant message in the error I think is
couldn't deduce template parameter ‘R’`
g++ full message:
main2.cpp: In function ‘int main()’:
main2.cpp:21:12: error: no matching function for call to ‘f(<unresolved overloaded function type>)’
f(&X::get);
^
main2.cpp:18:25: note: candidate: template<class R, class auto:1> auto f(auto:1 (X::*)(int) const)
template <class R> auto f(auto (X::*)(int) const -> R) {}
^
main2.cpp:18:25: note: template argument deduction/substitution failed:
main2.cpp:21:12: note: types ‘auto:1 (X::)(int) const’ and ‘int (X::)(int)’ have incompatible cv-qualifiers
f(&X::get);
^
main2.cpp:21:12: note: couldn't deduce template parameter ‘R’
<builtin>: recipe for target 'main2' failed
make: *** [main2] Error 1
As pointed in the question this is a gcc bug which was beed fixed in version 6
gcc.gnu.org/bugzilla/show_bug.cgi?id=69139

How to pass array to function template with reference

I am learning c++ template concepts. I do not understand the following.
#include <iostream>
#include <typeinfo>
using namespace std;
template <typename T>
T fun(T& x)
{
cout <<" X is "<<x;
cout <<"Type id is "<<typeid(x).name()<<endl;
}
int main ( int argc, char ** argv)
{
int a[100];
fun (a);
}
What i am trying?
1) T fun (T & x)
Here x is a reference, and hence will not decayed 'a' into pointer type,
but while compiling , i am getting the following error.
error: no matching function for call to ‘fun(int [100])’
When I try non-reference, it works fine. As I understand it the array is decayed into pointer type.
C-style arrays are very basic constructs which are not assignable, copyable or referenceable in the way built-ins or user defined types are. To achieve the equivalent of passing an array by reference, you need the following syntax:
// non-const version
template <typename T, size_t N>
void fun( T (&x)[N] ) { ... }
// const version
template <typename T, size_t N>
void fun( const T (&x)[N] ) { ... }
Note that here the size of the array is also a template parameter to allow the function to work will all array sizes, since T[M] and T[N] are not the same type for different M, N. Also note that the function returns void. There is no way of returning an array by value, since the array is not copyable, as already mentioned.
The problem is in the return type: you cannot return an array because arrays are non-copiable. And by the way, you are returning nothing!
Try instead:
template <typename T>
void fun(T& x) // <--- note the void
{
cout <<" X is "<<x;
cout <<"Type id is "<<typeid(x).name()<<endl;
}
And it will work as expected.
NOTE: the original full error message (with gcc 4.8) is actually:
test.cpp: In function ‘int main(int, char**)’:
test.cpp:17:10: error: no matching function for call to ‘fun(int [100])’
fun (a);
^
test.cpp:17:10: note: candidate is:
test.cpp:7:3: note: template<class T> T fun(T&)
T fun(T& x)
^
test.cpp:7:3: note: template argument deduction/substitution failed:
test.cpp: In substitution of ‘template<class T> T fun(T&) [with T = int [100]]’:
test.cpp:17:10: required from here
test.cpp:7:3: error: function returning an array
The most relevant line is the last one.