GCC template argument deduction/substitution failed - c++

The code below compiles on MSVC but fails on GCC (4.6.3). Why does it fail and what should I do to fix it?
#include <array>
class Foo {
public:
template<typename T, int N>
operator std::array<T, N>() const {
return std::array<T, N>();
}
};
int main(){
Foo val;
// both of the following lines fail on GCC with error:
// "no matching function call...", ultimately with a note:
// "template argument deduction/substitution failed"
auto a = val.operator std::array<int, 2>();
static_cast<std::array<int, 2>>(val);
return 0;
}
EDIT: The following code, however, does compile (on both compilers), despite passing in an int for std::array's template parameter.
template<int N, typename T>
struct Bar {
std::array<T, N> buf;
};
int main()
{
auto x = Bar<3, double>();
return 0;
}

If you read the full text of the error messages you get, the compiler is complaining because the type for N in your template class is int, while the second parameter of std::array is std::size_t, which is an unsigned long on your system.
Changing your template's declaration to use std::size_t N will fix the problem.
MSVC is not complaining possibly because it recognizes that the value "2" works for either case, or because of a compiler bug.

Related

Cannot get pointer to member funtion out of decltype

I've observed I cannot do &decltype(c)::f to get a pointer to member function f using a class instance c, but I can do &C::f to get that pointer to member function, using the class type C, which I believe is the same as decltype(c).
See this minimal example:
struct C{
int f()
{
return 5;
}
} c;
template<typename T, T t, typename S, S*s> void callCf()
{
(s->*t)();
}
int main()
{
callCf<decltype(&decltype(c)::f),&decltype(c)::f,C,&c>();
}
Compiling this gives:
In function 'int main()':
15:3: error: parse error in template argument list
15:58: error: no matching function for call to 'callCf()'
15:58: note: candidate is:
8:49: note: template<class T, T t, class S, S* s> void callCf()
8:49: note: template argument deduction/substitution failed:
15:58: error: template argument 2 is invalid
Using the following works as expected:
int main()
{
callCf<decltype(&decltype(c)::f),&C::f,C,&c>();
}
Even this works:
int main()
{
using tC = decltype(c);
callCf<decltype(&decltype(c)::f),&tC::f,C,&c>();
}
This also works:
template<typename T>
struct forward_type{
typedef T type;
};
int main()
{
callCf<decltype(&decltype(c)::f),&forward_type<decltype(c)>::type::f,C,&c>();
}
My question is: why is it not possible to use decltype to obtain a pointer to member function like this &decltype(c)::f?
Edit: #Paul Sanders has shown in the comments that the minimal example works in c++17. I'm still using c++14. Does c++17 include some changes to the language that allow my minimal example to compile?
c is an lvalue, so decltype(c) will not return the C type itself, which is why decltype(c)::f does not work. decltype(c) will actually return a C& reference type instead:
If the argument is any other expression of type T, and
...
b) if the value category of expression is lvalue, then decltype yields T&;
...
You can use std::remove_reference/_t to get the C type from C&, eg:
int main()
{
callCf<
decltype(&std::remove_reference_t<decltype(c)>::f),
&std::remove_reference_t<decltype(c)>::f,
std::remove_reference_t<decltype(c)>,
&c
>();
}
Live Demo
Which can then be simplified with a using statement:
int main()
{
using tC = std::remove_reference_t<decltype(c)>;
callCf<decltype(&tC::f), &tC::f, tC, &c>();
}
Live Demo

"could not match 'T [S]' against 'std::vector<int>'" for some functions but not others with same parameter list

For a homework assignment, I'm trying to create my own versions of std::find, std::begin, std::end, and std::size.
I've written some code that looks like this:
#include <vector>
template <typename I, typename T>
I find(const I& beg, const I& end, const T& sought)
{/* ... */}
template <typename T, size_t S>
T* begin(T (&a)[S])
{return &a;}
template <typename T, size_t S>
T* end(T (&a)[S])
{return &a + S;}
template <typename T, size_t S>
constexpr size_t size(T (&)[S])
{return S;}
int main()
{
std::vector<int> vec = {0, 1, 2, 3};
// ...
// test not-found case (and `size()`)
find(begin(vec), end(vec), size(vec));
// ...
return 0;
}
(size_t should implicitly convert to int)
However when I compile, clang gives off the following error:
$ clang++ -o program ./*.cpp -std=c++11 -Wall -Wextra -Wpedantic -Wconversion -Wnon-virtual-dtor
./main.cpp:##:##: error: no matching function for call to 'size'
find(begin(vec), end(vec), size(vec)
^~~~
./main.cpp:##:##: note: candidate template ignored: could not match 'T [S]' against 'std::vector<int>'
constexpr size_t size(T (&)[S])
^
1 error generated.
What really baffles me is that both size() and begin()/end() have the exact same template structure and parameter list, and yet the former throws a compile error while the latters don't when given the same input.
I don't think the different return type is the issue, since if it was find() would be complaining, not size().
So how is size() different from the other functions that it would throw this error with the same template structure, parameter list, and input?
None of your begin/end/size templates match, because they only match for raw arrays (type T[S]) and not for the type you are using (std::vector<T>). You only get one error because the calls to begin and end will match the functions std::begin and std::end, due to argument dependent lookup. There is no std::size function (in C++11), so the only possible match for size is your size function which doesn't match, so you get an error.

Failure to deduce template argument std::function from lambda function

While exploring templates in C++, I stumbled upon the example in the following code:
#include <iostream>
#include <functional>
template <typename T>
void call(std::function<void(T)> f, T v)
{
f(v);
}
int main(int argc, char const *argv[])
{
auto foo = [](int i) {
std::cout << i << std::endl;
};
call(foo, 1);
return 0;
}
To compile this program, I am using the GNU C++ Compiler g++:
$ g++ --version // g++ (Ubuntu 6.5.0-1ubuntu1~16.04) 6.5.0 20181026
After compiling for C++11, I get the following error:
$ g++ -std=c++11 template_example_1.cpp -Wall
template_example_1.cpp: In function ‘int main(int, const char**)’:
template_example_1.cpp:15:16: error: no matching function for call to ‘call(main(int, const char**)::<lambda(int)>&, int)’
call(foo, 1);
^
template_example_1.cpp:5:6: note: candidate: template<class T> void call(std::function<void(T)>, T)
void call(std::function<void(T)> f, T v)
^~~~
template_example_1.cpp:5:6: note: template argument deduction/substitution failed:
template_example_1.cpp:15:16: note: ‘main(int, const char**)::<lambda(int)>’ is not derived from ‘std::function<void(T)>’
call(foo, 1);
^
(same for C++14 and C++17)
From the compiler error and notes I understand that the compiler failed to deduce the type of the lambda, since it cannot be matched against std::function.
Looking at previous questions (1, 2, 3, and 4) regarding this error, I am still confused about it.
As pointed out in answers from questions 3 and 4, this error can be fixed by explicitly specifying the template argument, like so:
int main(int argc, char const *argv[])
{
...
call<int>(foo, 1); // <-- specify template argument type
// call<double>(foo, 1) // <-- works! Why?
return 0;
}
However, when I use other types instead of int, like double, float, char, or bool, it works as well, which got me more confused.
So, my questions are as follow:
Why does it work when I explicitly specify int (and others) as the template argument?
Is there a more general way to solve this?
A std::function is not a lambda, and a lambda is not a std::function.
A lambda is an anonymous type with an operator() and some other minor utility. Your:
auto foo = [](int i) {
std::cout << i << std::endl;
};
is shorthand for
struct __anonymous__type__you__cannot__name__ {
void operator()(int i) {
std::cout << i << std::endl;
}
};
__anonymous__type__you__cannot__name__ foo;
very roughly (there are actual convert-to-function pointer and some other noise I won't cover).
But, note that it does not inherit from std::function<void(int)>.
A lambda won't deduce the template parameters of a std::function because they are unrelated types. Template type deduction is exact pattern matching against types of arguments passed and their base classes. It does not attempt to use conversion of any kind.
A std::function<R(Args...)> is a type that can store anything copyable that can be invoked with values compatible with Args... and returns something compatible with R.
So std::function<void(char)> can store anything that can be invoked with a char. As int functions can be invoked with a char, that works.
Try it:
void some_func( int x ) {
std::cout << x << "\n";
}
int main() {
some_func('a');
some_func(3.14);
}
std::function does that some conversion from its signature to the callable stored within it.
The simplest solution is:
template <class F, class T>
void call(F f, T v) {
f(v);
}
now, in extremely rare cases, you actually need the signature. You can do this in c++17:
template<class T>
void call(std::function<void(T)> f, T v) {
f(v);
}
template<class F, class T>
void call(F f_in, T v) {
std::function f = std::forward<F>(f_in);
call(std::move(f), std::forward<T>(v));
}
Finally, your call is a crippled version of std::invoke from c++17. Consider using it; if not, use backported versions.

Clang fails to initialize static const template member

In order to force the execution of a template method at program start one can initialize a static member with a static method. Then the method is run at program start for every instantiation of the template class:
#include <cstdio>
template<typename t, t value>
struct dummy_user_t {};
template<int i>
struct my_struct_t
{
static int s_value;
// "use" s_value so it's initialized
using value_user_t = dummy_user_t<const int&, s_value>;
static int method()
{
printf("Hello %i!\n", i);
return 0;
}
};
// initialize s_value with method() to run it at program start
template<int i>
int my_struct_t<i>::s_value {my_struct_t<i>::method()};
// instantiate my_struct_t
template struct my_struct_t<6>;
int main()
{
// nothing here
}
The output will be Hello 6!
This code compiles on all three major compilers but when you make s_value const it won't work in clang anymore (3.4 - 7.0) while still working in MSVC and GCC:
<source>:19:52: error: no member 'method' in 'my_struct_t<6>'; it has not yet been instantiated
const int my_struct_t<i>::s_value {my_struct_t<i>::method()};
^
<source>:10:51: note: in instantiation of static data member 'my_struct_t<6>::s_value' requested here
using value_user_t = dummy_user_t<const int&, s_value>;
^
<source>:21:17: note: in instantiation of template class 'my_struct_t<6>' requested here
template struct my_struct_t<6>;
^
<source>:11:16: note: not-yet-instantiated member is declared here
static int method()
^
1 error generated.
Try it out yourself:
With non const int: https://godbolt.org/z/m90bgS
With const int: https://godbolt.org/z/D3ywDq
What do you think? Is there any reason clang is rejecting this or is it a bug?

Array trait causes template argument deduction failure

The following code does not compile with G++ (although I believe it should):
#include <iostream>
template <unsigned N>
struct foo_traits {
typedef const char ArrayArg[N];
typedef int Function (ArrayArg *);
};
template <unsigned N>
int foo (typename foo_traits<N>::Function *ptr) {
return ptr(&"good");
}
int bar (const char (*x)[5]) {
std::cout << *x << "\n";
return 0;
}
int main ()
{
return foo(bar);
}
I checked this with GCC 4.4 through 4.7, and I get a template argument deduction failure. With 4.7.1:
prog.cpp: In function ‘int main()’:
prog.cpp:21:19: error: no matching function for call to ‘foo(int (&)(const char (*)[5]))’
prog.cpp:21:19: note: candidate is:
prog.cpp:10:5: note: template<unsigned int N> int foo(typename foo_traits<N>::Function*)
prog.cpp:10:5: note: template argument deduction/substitution failed:
prog.cpp:21:19: note: couldn't deduce template parameter ‘N’
If I use an explicit template argument (i.e., foo<5>(bar)), it compiles fine. If I use a version of the code without the typedefs, it compiles fine:
#include <iostream>
template <unsigned N>
int fixfoo (int (*ptr) (const char (*)[N])) {
return ptr(&"good");
}
int bar (const char (*x)[5]) {
std::cout << *x << "\n";
return 0;
}
int main ()
{
return fixfoo(bar);
}
Is the failing code supposed to compile (i.e., did I make a silly mistake)?
int foo(typename foo_traits<N>::Function *ptr);
The signature makes it a non-deductible context, so you must include the template arguments so that the value N is known and so consequentially the type of the pointer ptr be known as well.
Your second example compiles because the type of the signature through bar can be deduced.