Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Template argument deduction: which compiler is right here?

Consider the following code:

template<int N>
class Vector
{
};

#include <array>

template<int N>
void doWork(const Vector<N>&, const std::array<int,N>&)
{
}

int main()
{
    std::array<int,3> arr;
    Vector<3> vec;
    doWork(vec,arr);
}

Here Vector represents a class which is defined in a third-party library, and std::array is known to take its element count as std::size_t.

I've tried compiling this with clang-3.6 and g++-5.1. Clang worked without any complaint, while g++ gives the following error:

test.cpp: In function ‘int main()’:
test.cpp:17:19: error: no matching function for call to ‘doWork(Vector<3>&, std::array<int, 3ul>&)’
     doWork(vec,arr);
                   ^
test.cpp:9:6: note: candidate: template<int N> void doWork(const Vector<N>&, const std::array<int, N>&)
 void doWork(const Vector<N>&, const std::array<int,N>&)
      ^
test.cpp:9:6: note:   template argument deduction/substitution failed:
test.cpp:17:19: note:   mismatched types ‘int’ and ‘long unsigned int’
     doWork(vec,arr);
                   ^
test.cpp:17:19: note:   ‘std::array<int, 3ul>’ is not derived from ‘const std::array<int, N>’

I can work around this by doing a cast of N to std::size_t in second parameter of doWork() or calling doWork<3>(), but this wouldn't educate me.

So I rather ask first: which compiler is right here? Am I really doing something wrong in the code (so clang is too permissive), or is it indeed valid C++ (so that g++ has a bug)?

like image 451
Ruslan Avatar asked Oct 01 '15 15:10

Ruslan


People also ask

What is template argument deduction?

Template argument deduction is used in declarations of functions, when deducing the meaning of the auto specifier in the function's return type, from the return statement.

What is template argument in C++?

A template parameter is a special kind of parameter that can be used to pass a type as argument: just like regular function parameters can be used to pass values to a function, template parameters allow to pass also types to a function.

What is the task of compiler when handling template?

When you call a function template, the compiler tries to deduce the template type. Most of the time it can do that successfully, but every once in a while you may want to help the compiler deduce the right type — either because it cannot deduce the type at all, or perhaps because it would deduce the wrong type.

What is CTAD C++?

Class Template Argument Deduction (CTAD) is a C++17 Core Language feature that reduces code verbosity. C++17's Standard Library also supports CTAD, so after upgrading your toolset, you can take advantage of this new feature when using STL types like std::pair and std::vector.


1 Answers

I believe gcc is correct here, if we go to the draft C++11 standard section 14.8.2.5 [temp.deduct.type] it says:

If, in the declaration of a function template with a non-type template-parameter, the non-type templateparameter is used in an expression in the function parameter-list and, if the corresponding template-argument is deduced, the template-argument type shall match the type of the template-parameter exactly, except that a template-argument deduced from an array bound may be of any integral type.144 [ Example:

template<int i> class A { /* ... */ };
template<short s> void f(A<s>);
void k1() {
A<1> a;
f(a); // error: deduction fails for conversion from int to short
f<1>(a); // OK
}

[...]

and we can see if we change your code to this:

doWork<3>(vec,arr);

gcc does not issue an error and neither does clang.

If we try this example:

template<int N>
void doWorkB( std::array<int,N>&)
{
}

//...

doWorkB(arr);

clang now produces an error (see it live):

note: candidate template ignored: substitution failure : deduced non-type template argument does not have the same type as the its corresponding template parameter ('unsigned long' vs 'int')
void doWorkB( std::array<int,N>&)
     ^

Your original case also breaks in clang if we swap the parameter order:

void doWork( const std::array<int,N>&, const Vector<N>& )
like image 99
Shafik Yaghmour Avatar answered Oct 26 '22 07:10

Shafik Yaghmour