Inconsistency in function type decomposition between variable / non-invariant patterns?

Given the pattern of an invariant function:

template<class T> void f(void(t)(T)); 

And some simple functions:

 void f1(int); void f2(char); 

It works:

 f(f1); 

Type t becomes void (*)(int) .

However, the variation analogue:

 template<class... T> void f(void(...t)(T)); // call f(f1, f2); 

does not work. Compilers (gcc and clang) complain about inconsistent types void(T) and void (*)(int) . See DEMO .

Note that if * added explicitly, it works as it should:

 template<class... T> void f(void(*...t)(T)); 

So, why can the non-invariant decompose the type of function, and the variable can not?

+6
source share
3 answers

AFAICS, the code is fine (also confirmed by VC ++ and ICC . In the end, the output of the template argument seems to work with function types in the same way as with function pointers or reference types; [temp.deduct.type] / 18 :

The template argument can be inferred from the [...] function.

[temp.deduct.call] / 1 :

For the package of function parameters that occurs at the end of the parameter-declaration-list, subtraction is performed for each remaining argument of the call, taking type P identifier of the declarator as the corresponding parameter of the parameter of the function template. Each deduction displays the template arguments for subsequent positions in the parameter template packages extended by the parameter package function.

In particular, the last paragraph confirms that there is some inconsistency, since the (unsuccessful) output of the packet T in the second case reduces to the (successful) deduction in case 1.

I assume that Clang and GCC decay parameter types for function templates right during the declaration, but refuse to do this when the parameter is a package extension (and then fails). The Clang error message when changing the call of the sample to f(f1) is

Note: the candidate template is ignored: could not match 'void (T)' with 'void (*)(int)'

Thus, the argument actually decomposes before deduction.

+3
source

Because your syntax is not quite right.

 template<class... T> void f(void(t)(T...)); void f1(int); void foo() { f(f1); } 

Tested with gcc 6.1.1. Compiles without errors.

In the non-invariant version, you use the template parameter as a parameter for the arguments of the passed function parameter.

Therefore, for the version with the variable version, where the parameter package is expanded.

0
source

Is this explained?

 template<class... T> void f(void(*...t)(T)) { std::cout << "Ptr to functions" << std::endl; } template<class... T> void g(void(&...t)(T)) { std::cout << "Ref to functions" << std::endl; } template <class... T> void h(void(...t)(T)) { std::cout << "Mmmm... potential of confusion" << std::endl; } void s1(int) { } void s2(long) { } #include <type_traits> int main() { // this compiles Ok. The compiler knows // pointer to functions will be passed // and can infer their correspondent T f(s1,s2); // this compiles Ok. The compiler knows that // reference to functions will be passed // and can infer their correspondent T g(s1,s2); h(s1,s2); // ^^^^^^^^^ this will cause a compilation error telling: // template argument deduction/substitution failed: // mismatched types 'void(T)' and 'void (*)(int)' // The compiler can't decide how the function-type parameters are passed // by ptr, by ref, one by ref other by ptr? As such // cannot deduce their correspondent T in the argpack // however, this will compile OK!!! // The s1/s2 correspondent T-es in argpack are clearly specified, // not a problem. h<int,long>(s1,s2); return 0; } 
0
source

All Articles