Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trailing class template arguments not deduced

The code below fails to compile with gcc 7.1.0, which complains about providing the wrong number of template arguments in the second line of main. This version of GCC is supposed to implement template argument deduction of class templates.

I think the compiler should be able to deduce the class template argument T2 for Bar, which means that I shouldn't have to explicitly specify both arguments (Bar<int, int>) given paragraph 17.8.1.3 of the C++17 draft which says, "Trailing template arguments that can be deduced (17.8.2) or obtained from default template-arguments may be omitted from the list of explicit template-arguments."

Am I wrong? Is the compiler wrong? Is this an oversight or a deliberate design?

template <typename T>
struct Foo {
    Foo(T t) {}
};

template <typename T1, typename T2>
struct Bar {
    Bar(T2 t) {}
};

template <typename T1, typename T2>
void bar(T2 t) {}

int main(int argc, char **argv) {

    Foo(42); // Works

    Bar<int>(42); // Fails to compile with "wrong number of
                  // template arguments (1, should be 2)"

    bar<int>(42); // Works
}
like image 832
tweej Avatar asked Aug 06 '17 05:08

tweej


1 Answers

This is expected behavior; unlike template argument deduction (for function templates), class template argument deduction (since C++17) only works when no template arguments are provided.

Class template argument deduction is only performed if no template arguments are provided. If at least one argument is specified, deduction does not take place.

std::tuple t(1, 2, 3);              // OK: deduction
std::tuple<int,int,int> t(1, 2, 3); // OK: all arguments are provided
std::tuple<int> t(1, 2, 3);         // Error: partial deduction

That means for your example you can't take advantage of class template argument deduction and have to specify all the template arguments. If you want class template argument deduction taking effect you have to specify none, but the template parameter T1 can't be deduced.

On the other hand, the following code would work.

template <typename T1, typename T2>
struct Bar {
    Bar(T1, T2) {}   // make it possible to deduce T1
};

int main(int argc, char **argv) {
    Bar bar(42, 42); // take advantage of class template argument deduction
}
like image 175
songyuanyao Avatar answered Nov 14 '22 21:11

songyuanyao