Are reference non-type template parameters deduced by decltype(auto) forwardable in case of template template parameter
Asked Answered
S

1

9

Yet another decltype(auto) template template-parameter question. This time minimal code I was able to create to reproduce the error looks like this:

template <template <decltype(auto)> class TT, decltype(auto) V>
void foo(TT<V>) {
};

template <decltype(auto)>
struct Bar{};

int x;

int main() {
    foo(Bar<(x)>{});
}

This in [clang] results in:

prog.cc:11:5: error: no matching function for call to 'foo'
    foo(Bar<(x)>{});
    ^~~
prog.cc:2:6: note: candidate template ignored: substitution failure [with TT = Bar]: non-type template argument is not a constant expression
void foo(TT<V>) {
     ^
1 error generated.

[gcc] accepts the code.

To my understanding the code is well-formed and clang is buggy in its interpretation, but need the confirmation before submitting a bug to lvvm. Am I right?

Shoreless answered 20/9, 2017 at 17:9 Comment(7)
@StoryTeller I get your point. I'll try to edit the question to be less suggestive when get back to computerShoreless
@StoryTeller I don't understand your comment. TT is a template template-parameter, that deduces to Bar just fine? clang's problem is in deducing VGwyn
@Gwyn - My comment was about the mcve. I can swear TT was a plain decltype(auto). Not a template. Appearantly I just misread.Muncey
Anyway, I'm not by a computer, but I too would be really surprised if this isn't officially well-formed.Muncey
Simpler example: have foo just be template <decltype(auto) V> void foo(Bar<V> ) { } - same behavior, just one less variableGwyn
@Barry: I think that pretty much solidifies it as a clang bug, yeah?Wilmer
I'll try to find appropriate standard fragment and get back with filed bug, not sure if I will be able do it today. Thanks!Shoreless
S
1

According to error clang does not have a problem with deducing template template-parameter which is also standard compliant - [temp.arg.template]/3 (empasis mine):

A template-argument matches a template template-parameter P when P is at least as specialized as the template-argument A. If P contains a parameter pack, then A also matches P if each of A's template parameters matches the corresponding template parameter in the template-parameter-list of P. Two template parameters match if they are of the same kind (type, non-type, template), for non-type template-parameters, their types are equivalent ([temp.over.link]), and for template template-parameters, each of their corresponding template-parameters matches, recursively. When P's template-parameter-list contains a template parameter pack, the template parameter pack will match zero or more template parameters or template parameter packs in the template-parameter-list of A with the same type and form as the template parameter pack in P (ignoring whether those template parameters are template parameter packs)

Now lets make sure the Bar<(x)>{} should be deduced as reference. This is covered by [dcl.type.auto.deduct]/5 and [dcl.type.simple]/4.

Finally lets check if we actually can use the reference to the variable with linkage as a template argument [temp.arg.nontype]/2:

A template-argument for a non-type template-parameter shall be a converted constant expression of the type of the template-parameter. For a non-type template-parameter of reference or pointer type, the value of the constant expression shall not refer to (or for a pointer type, shall not be the address of):

  • a subobject,
  • a temporary object,
  • a string literal,
  • the result of a typeid expression, or
  • a predefined ­­func_­_­ variable.

[ Note: If the template-argument represents a set of overloaded functions (or a pointer or member pointer to such), the matching function is selected from the set ([over.over]). — end note  ]

The deduced argument fulfils the requirements. This makes the code well-formed and suggests clang's bug.

Filed bug 34690

Shoreless answered 21/9, 2017 at 13:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.