This question already has answers here:
Why does the implicit type conversion not work in template deduction?
(2 answers)
Implicit type conversion with template
(4 answers)
Template function argument deduction with an implicit conversion
(1 answer)
Closed 10 days ago.
I'm using C++20.
template <typename T> struct Foo {};
template <typename T> struct Bar {
constexpr operator Foo<T>() const { return {}; }
};
template <typename T> void foo(Foo<T>) {}
void bar(Foo<int>) {}
int main() {
Bar<int> b;
bar(b); // fine
foo(b); // error
}
Godbolt link so you can test online:
https://godbolt.org/z/vYjs5nMxh
The error
<source>: In function 'int main()':
<source>:13:6: error: no matching function for call to 'foo(Bar<int>&)'
13 | foo(b);
| ~~~^~~
<source>:7:28: note: candidate: 'template<class T> void foo(Foo<T>)'
7 | template <typename T> void foo(Foo<T>) {}
| ^~~
<source>:7:28: note: template argument deduction/substitution failed:
<source>:13:6: note: 'Bar<int>' is not derived from 'Foo<T>'
13 | foo(b);
| ~~~^~~
Compiler returned: 1
Is there a way to get deduction to work without requiring inheritance?
This question already has answers here:
SFINAE: std::enable_if as function argument
(2 answers)
Closed 10 months ago.
The minimal example is rather short:
#include <iostream>
#include <array>
#include <type_traits>
struct Foo{
//template <class C>
//Foo(C col, typename std::enable_if<true,C>::type* = 0){
// std::cout << "optional argument constructor works" << std::endl;
//}
template <class C>
Foo(typename std::enable_if<true, C>::type col){
std::cout << "no optional argument constructor works NOT" << std::endl;
}
};
int main()
{
auto foo = Foo(std::array<bool,3>{0,0,1});
}
The first constructor works as expected. However the second constructor does not compile and I get
error: no matching function for call to ‘Foo::Foo(std::array)’
However the given explanation
note: template argument deduction/substitution failed
does not help, as std::enable_if<true, C>::type should be C and such the first argument in both constructors should look exactly the same to the compiler. I'm clearly missing something. Why is the compiler behaving differently and are there any other solution for constructors and enable_if, which do not use an optional argument?
Complete error message:
main.cpp:18:45: error: no matching function for call to ‘Foo::Foo(std::array)’
18 | auto foo = Foo(std::array<bool,3>{0,0,1});
| ^
main.cpp:11:5: note: candidate: ‘template Foo::Foo(typename std::enable_if::type)’
11 | Foo(typename std::enable_if<true, C>::type col){
| ^~~
main.cpp:11:5: note: template argument deduction/substitution failed:
main.cpp:18:45: note: couldn’t deduce template parameter ‘C’
18 | auto foo = Foo(std::array<bool,3>{0,0,1});
| ^
main.cpp:5:8: note: candidate: ‘constexpr Foo::Foo(const Foo&)’
5 | struct Foo{
| ^~~
main.cpp:5:8: note: no known conversion for argument 1 from ‘std::array’ to ‘const Foo&’
main.cpp:5:8: note: candidate: ‘constexpr Foo::Foo(Foo&&)’
main.cpp:5:8: note: no known conversion for argument 1 from ‘std::array’ to ‘Foo&&’
Template argument deduction does not work this way.
Suppose you have a template and a function using a type alias of that template:
template <typename T>
struct foo;
template <typename S>
void bar(foo<S>::type x) {}
When you call the function, eg foo(1) then the compiler will not try all instantiations of foo to see if any has a type that matches the type of 1. And it cannot do that because foo::type is not necessarily unambiguous. It could be that different instantiations have the same foo<T>::type:
template <>
struct foo<int> { using type = int; };
template <>
struct foo<double> { using type = int; };
Instead of even attempting this route and potentially resulting in ambiguity, foo<S>::type x is a nondeduced context. For details see What is a nondeduced context?.
Template argument deduction fails because C appears in a Non-deduced context. The linked page lists
The nested-name-specifier (everything to the left of the scope resolution operator ::) of a type that was specified using a qualified-id
as a non-deduced context.
They also mention another example further down:
For example, in A<T>::B<T2>, T is non-deduced because of rule #1 (nested name specifier), and T2 is non-deduced because it is part of the same type name, but in void(*f)(typename A<T>::B, A<T>), the T in A<T>::B is non-deduced (because of the same rule), while the T in A<T> is deduced.
The other answers already explain why argument deduction did not work here. If you want to enable_if your constructor, you can simply put the condition in the template list like this:
struct Foo{
// your condition here ---v
template <class C, typename std::enable_if_t< true >* = nullptr>
Foo(C col) {
std::cout << "constructor" << std::endl;
}
};
This question already has answers here:
Where and why do I have to put the "template" and "typename" keywords?
(8 answers)
Closed 8 years ago.
(This question is only a duplicate of the other question if you already know the answer!)
(Please note my follow-up question: Why is no template keyword needed if an unrelated global template function with same name exists?)
I get a compiler error at the indicated line when I try to compile templated C++ code with this structure:
template <int N>
struct A {
template <int i>
void f() {};
};
template <int N>
struct B {
A<N> a;
B(A<N>& a) : a(a) {}
void test() {
a.f<1>(); // does not compile
}
};
int main() {
A<2> a;
a.f<1>(); // works fine
B<2> b(a);
b.test();
}
g++ says:
test2.cpp: In member function ‘void B<N>::test()’:
test2.cpp:14: error: expected primary-expression before ‘)’ token
test2.cpp: In member function ‘void B<N>::test() [with int N = 2]’:
test2.cpp:22: instantiated from here
test2.cpp:14: error: invalid operands of types ‘<unresolved overloaded function type>’ and ‘int’ to binary ‘operator<’
clang++ says:
test2.cpp:14:16: error: expected expression
a.f<1>(); // does not compile
^
1 error generated.
The same expression works in the context of main(), but not within the test() method of the templated class B, which has an instance of A as a private variable. I am pretty clueless why this doesn't work.
You have to use a.template f<1>(); inside of b.test().
I have no problem passing the address of a function template specialization to a regular template function:
template <typename T>
void f(T) {}
template <typename A, typename B>
void foo(A, B) {}
int main()
{
foo(&f<int>, &f<float>);
}
However, when I try to pass the same specializations to a variadic template:
template <typename T>
void f(T) {}
template <typename... A>
void bar(A...) {}
int main()
{
bar(&f<int>, &f<float>);
}
I get the following compiler errors with GCC (I tried 4.6.1 and 4.7.0):
test.cpp: In function 'int main()':
test.cpp:9:27: error: no matching function for call to 'bar(<unresolved overloaded function type>, <unresolved overloaded function type>)'
test.cpp:9:27: note: candidate is:
test.cpp:5:6: note: template<class ... A> void bar(A ...)
test.cpp:5:6: note: template argument deduction/substitution failed:
Why am I getting these errors?
Looks like it might be a bug in GCC that is possibly fixed in GCC 4.6.2 (I say possibly because it's not exactly the same, but does involve getting the address of a variadic template function).
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Why are qualifiers of template arguments stripped when deducing the type?
Consider the following C++ code:
void f(int&);
template <typename T> void tpl(void (*)(T), T);
void bar(int& x)
{
tpl(&f, x);
}
Compilation using GCC 4.6.0 fails with the following error message:
fntpl.cpp: In function ‘void bar(int&)’:
fntpl.cpp:7:11: error: no matching function for call to ‘tpl(void (*)(int&), int&)’
fntpl.cpp:7:11: note: candidate is:
fntpl.cpp:3:46: note: template<class T> void tpl(void (*)(T), T)
If I state the template parameters explicitely (tpl<int&>(&f, x)), it works. Why doesn't template argument deduction work in this case?
Because these are fundamentally different
void f(int&);
and
void (*)(T)
the compiler has only deduced that T is int, so it looks for:
void f(int);
which is nothing like your intention, change the function pointer to this:
template <typename T> void tpl(void (*)(T&), T);
And the compiler will be happy...