Consider the following code
template<bool b, typename T> void foo(const T& t = []() {}) {
// implementation here
}
void bar() {
foo<true>([&](){ /* implementation here */ }); // this compiles
foo<true>(); // this doesn't compile
}
In the case that doesn't compile I get the following errors:
error C2672: 'foo': no matching overloaded function found
error C2783: 'void foo(const T&)': could not deduce template argument for 'T'
I think it's clear what I want to achieve: let foo be called with and without a client-provided lambda. The compiler is MSVC++2017 version 15.4.4 toolset v141.
Default function arguments are not part of the template argument deduction process. To quote [temp.deduct.partial]/3:
The types used to determine the ordering depend on the context in
which the partial ordering is done:
In the context of a function call, the types used are those function parameter types for which the function call has arguments.
141
141) Default arguments are not considered to be arguments in this
context; they only become arguments after a function has been
selected.
That bullet and note indicate that since you didn't provide an argument for t in the call to foo, the type T cannot be deduced. The default lambda argument can only be taken into account if the function is selected to be called, not before.
The solution, as all the others have noted, is to provide an overload without parameters, that will call the templated one with the default lambda you have in mind.
Another (very efficient) way - default T to be a null functor.
// no_op is a function object which does nothing, regardless of how many
// arguments you give it. It will be elided completely unless you compile with
// -O0
struct no_op
{
template<class...Args>
constexpr void operator()(Args&&...) const {}
};
// foo defaults to using a default-constructed no_op as its function object
template<bool b, typename T = no_op> void foo(T&& t = T())
{
// implementation here
t();
}
void bar() {
foo<true>([&](){ std::cout << "something\n"; }); // this compiles
foo<true>(); // this now compiles
}
The compiler uses the arguments passed to deduce the template type. If there's no arguments, then how would the compiler be able to deduce the template type?
You can use overloading instead of default arguments here.
The overloaded non-argument function can simply call the function with the "default" argument:
template<bool b, typename T> void foo(const T& t) {
// implementation here
}
template<bool b> void foo() {
foo<b>([]() {});
}
Consider overloading it directly:
template <bool b>
void foo(void) {
foo([](){});
}
See CppReference:
Non-deduced contexts
4) A template parameter used in the parameter type of a function parameter that has a default argument that is being used in the call for which argument deduction is being done:
Type template parameter cannot be deduced from the type of a function default argument:
template void f(T = 5, T = 7);
void g()
{
f(1); // OK: calls f<int>(1, 7)
f(); // error: cannot deduce T
f<int>(); // OK: calls f<int>(5, 7)
}
You are trying to say something that makes no sense. You are asking the compiler to guess T from your arguments, but then you do not provide any argument.
The following code does compile, and does what you want:
template<bool b, typename T> void foo(const T& t) {
// implementation here
}
template<bool b> void foo() {
foo<b>([]() {}); // Call actual implementation with empty lambda
}
void bar() {
foo<true>([&](){ /* implementation here */ }); // this compiles
foo<true>(); // this now compiles as well
}
Related
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, &&)
It seems that GCC treats expanding an empty parameter pack A into another
parameter pack B differently than manually entering an empty parameter pack
B. Example:
void baz();
void baz(int);
template<typename... Args, typename R>
void bar(R (*)(Args...));
template<typename... Args>
void foo()
{
bar<Args...>(baz);
}
int main()
{
foo<>(); // Deduces baz()
//bar<>(baz); // Ambiguous
foo<int>(); // Deduces baz(int)
bar<int>(baz); // Deduces baz(int)
//foo<void>(); // Ambiguous
//bar<void>(baz); // Ambiguous
}
Is this behaviour standard conforming? You can see a live example of the difference here and here.
f<> doesn't force empty pack, just tells the first 0 arguments of the template argument.
Clang rejects foo<>() (Demo) as it can't decide which overload of baz for bar<>(baz);
The fact that gcc accepts it seems to be a bug.
Is it possible to have functions generated from template as f() and f<T>() ?
I want to call f most of the time with the type specified, such as:
f<string>();
f<int>();
but I also need to call it like this:
f();
and the type when not specified it should be string. Is this possible?
template <typename T>
void f() { ... }
void f() { f<string>(); }
You can give default type for template arguments:
template<class T=std::string>
foo()
Note: If you give default argument to template class, you must declare the default version with Foo<>. This is not necessary when calling templated functions; You can call the default version without angle brackets: foo()
Another note: This works for functions because of template argument deduction. Quote from the standard (January 2012 draft §14.8.2.5) emphasis mine:
The resulting substituted and adjusted function type is used as the
type of the function template for template argument deduction. If a
template argument has not been deduced, its default template argument,
if any, is used. [ Example:
template <class T, class U = double>
void f(T t = 0, U u = 0);
void g() {
f(1, ’c’); //f<int,char>(1,’c’)
f(1); //f<int,double>(1,0)
f(); //error: T cannot be deduced
f<int>(); //f<int,double>(0,0)
f<int,char>(); //f<int,char>(0,0)
}
#include <string>
template <typename T=std::string>
void f() {}
int main()
{
f();
}
In the following :
template<typename Type>
struct MyClass
{
template<typename OtherType> MyClass(const MyClass<OtherType>& x);
template<typename OtherType = Type> void test(const MyClass<OtherType>& x);
};
In the function test what is done between :
Case 1 : The default parameter is priority : the conversion constructor MyClass<Type>(const MyClass<OtherType>& x) is implicitely called and MyClass<Type>::test<Type>(const MyClass<Type>& x) is called.
Case 2 : The deduced parameter is priority : MyClass<Type>::test<Type>(const MyClass<OtherType>& x) is called.
I think that the good answer is the second one, but I'm not sure. Can you confirm me that (and that this situation is well-defined by the standard) ?
EDIT : The test function is called by :
MyClass<double> d;
MyClass<unsigned int> ui;
d.test(ui); // <- So the question is : is ui implicitely
// converted to MyClass<double> or not ?
test will be called as
MyClass<double>::test(const MyClass<unsigned int> &)
i.e. there will be no conversion of ui from MyClass<unsigned int> to MyClass<double>.
A default template argument never overrides a given one. It is only used when no template argument is given and the compiler can't deduce it from the function arguments.
From the C++11 Standard:
(§14.8.2/5) The resulting substituted and adjusted function type is used as the type of the function template for template argument deduction. If a template argument has not been deduced, its default template argument, if any, is used. [ Example:
template <class T, class U = double>
void f(T t = 0, U u = 0);
void g() {
f(1, ’c’); // f<int,char>(1,’c’)
f(1); // f<int,double>(1,0)
f(); // error: T cannot be deduced
f<int>(); // f<int,double>(0,0)
f<int,char>(); // f<int,char>(0,0)
}
— end example ]
Consider this template function:
template<typename ReturnT>
ReturnT foo(const std::function<ReturnT ()>& fun)
{
return fun();
}
Why isn't it possible for the compiler to deduce ReturnT from the passed call signature?
bool bar() { /* ... */ }
foo<bool>(bar); // works
foo(bar); // error: no matching function call
A function pointer of type bool (*)() can be converted to std::function<bool()> but is not the same type, so a conversion is needed. Before the compiler can check whether that conversion is possible it needs to deduce ReturnT as bool, but to do that it needs to already know that std::function<bool()> is a possible conversion, which isn't possible until it deduces ReturnT ... see the problem?
Also, consider that bool(*)() could also be converted to std::function<void()> or std::function<int()> ... which should be deduced?
Consider this simplification:
template<typename T>
struct function
{
template<typename U>
function(U) { }
};
template<typename T>
void foo(function<T>)
{ }
int main()
{
foo(1);
}
How can the compiler know whether you wanted to create function<int> or function<char> or function<void> when they can all be constructed from an int?
std::function<bool()> bar;
foo(bar); // works just fine
C++ can't deduce the return type from your function bar because it would have to know the type before it could find all the constructors that take your function pointer.
For example, who's to say that std::function<std::string()> doesn't have a constructor taking a bool (*)()?
The function bar is of type bool (*)() or so, that is: a normal pre-C++11 function type. I'm not that confident in C++11, but I guess the compiler does not see the connection between bool (*)() and const std::function<ReturnT()>&, even when the first can be implicitly converted into the second for ReturnT = bool.