6

Consider the following variadic class template:

template <typename... Ts>
struct foo
{
    template <typename... Us>
    foo(Us...) { }
};

If I try to instantiate foo in the following way, both g++(trunk) and clang++(trunk) are happy:

auto o = foo{};

on godbolt.org


As soon as I switch to value-initialization with parentheses, g++ fails to compile (while clang++ is still happy):
auto o = foo();
error: cannot deduce template arguments for 'foo' from ()
     auto o = foo();
                  ^

on godbolt.org


Is this a g++ bug, or is there a difference in the way class template argument deduction is handled between {} and () initialization?

This also happens with a proper deduction guide: https://godbolt.org/g/qReXpM.

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
Vittorio Romeo
  • 90,666
  • 33
  • 258
  • 416
  • 2
    I'd say both compilers are wrong - there is no way to deduce `Ts` using `Us`... – W.F. Nov 11 '17 at 08:54
  • @W.F. also happens with a deduction guide. https://godbolt.org/g/qReXpM – Vittorio Romeo Nov 11 '17 at 08:57
  • 1
    @cpplearner this is definitely **not** a dup... – W.F. Nov 11 '17 at 08:57
  • 1
    @VittorioRomeo when you provide the deduction guides - you provide the mapping between types of your constructor and the template parameters so there is no analogy there... – W.F. Nov 11 '17 at 09:03
  • 1
    `g++` non-trunk says `error: missing template arguments before ‘{’ token` what is the difference between trunk and non-trunk? – Arash Nov 11 '17 at 09:06
  • 1
    cpplearner's dupe target is indeed a dupe if you include the deduction guides, but not if you don't, as that is another bug. – Rakete1111 Nov 11 '17 at 09:10
  • the difference in compilers behavior cannot be due to brace-initialization alone: if you replace the initialization with "auto o = new foo();" both compilers turn out happy ( note that due to [expr.new]/2 the deduction of “new foo()” should be the same as in “foo o = foo();”) – Massimiliano Janes Nov 11 '17 at 10:08
  • 2
    @W.F. if a "trailing template parameter pack" at the end of argument dedeuction remains undeduced, it's fallback-deduced as empty. It's long been a mystery what "trailing" is supposed to mean in http://eel.is/c++draft/temp.arg.explicit#3 . Compilers appear to not follow any "trailing" condition, for example in `template void f(U); f(10); /* compilers make T empty */`. – Johannes Schaub - litb Nov 11 '17 at 13:29
  • @JohannesSchaub-litb totally forgot about this bullet... Need to reconsider my answer then ;) – W.F. Nov 11 '17 at 13:41
  • @W.F. There might be a difference between `()` and `{}` w.r.t. overload resolution in class template argument deduction if the compilers consider the hypothetical class type to not have a default constructorl. Then `()` would not do overload-resolution, but just do zero-initialization. But `{}` will still do overload-resolution (not value initialization). – Johannes Schaub - litb Nov 11 '17 at 13:54
  • @JohannesSchaub-litb this would surely explain why gcc and clang both accept the code... I'm still however not entirely convinced... Is the code really well-formed in this case? – W.F. Nov 11 '17 at 14:07
  • EDIT: I must correct myself: As soon as there is no default constructor, we will also do overload resolution for `()` (to provoke an error, I guess). So it's still unclear to me. My best guess would then be that GCC just hasn't implemented http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1630 in all its glory yet. – Johannes Schaub - litb Nov 11 '17 at 14:07
  • Because it also happens with an explicit deduction guide, I would suspect there's somehting else going on, though. – Johannes Schaub - litb Nov 11 '17 at 14:14
  • @JohannesSchaub-litb What about [\[temp.res\]/8.3](http://eel.is/c++draft/temp#res-8.3). Wouldn't we face the situation where every valid specialization of the deduction guide template would require empty template parameter pack? – W.F. Nov 11 '17 at 14:23
  • 1
    @W.F. i think that's http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2067 . The user-written constructor can be instantiated for non-empty `Ts...` (it is also not a template itself but a templated entity.. i.e member of a template). – Johannes Schaub - litb Nov 11 '17 at 14:27

0 Answers0