1

I am learning C++ using the resources listed here. In particular, I have learnt that in C++20 we can have a class type as a non type template parameter. Now, to better understand the concept, I tried the following example that is accepted by msvc and gcc but rejected by clang. My question is which compiler is right?

Demo

struct Impl
{
  constexpr Impl(std::initializer_list<int>)
  {
      
  }
};
struct Bar{};
template<typename T, Impl impl>
struct Foo
{
    
};
int main()
{
    constexpr Foo<Bar, {1,2,3,4}> foo; //works in msvc & gcc but rejected in clang
    return 0;
}
Jason
  • 36,170
  • 5
  • 26
  • 60
Kal
  • 475
  • 1
  • 16
  • 1
    GCC and MSVC seems wrong. – Jason Aug 15 '22 at 15:59
  • `constexpr Foo foo;` works with all of the compilers in the link. My guess is clang isn't performing the conversion and requires it to be explicit. Not sure if that is the correct behavior or not. – NathanOliver Aug 15 '22 at 15:59
  • I know that `constexpr Foo foo;` works but i am not asking about that. I want to know whether `constexpr Foo foo;` is valid. – Kal Aug 15 '22 at 16:01
  • All __3__ compilers reject the code - live - https://godbolt.org/z/az5f68T9G – Richard Critten Aug 15 '22 at 16:09
  • 1
    @RichardCritten Not if you compile against C++20 which is required for this: https://godbolt.org/z/jeT7Ydb3r. Only clang fails that. – NathanOliver Aug 15 '22 at 16:14
  • @NathanOliver Yes, as non type template parameter require c++20. – Jason Aug 15 '22 at 16:15
  • @NathanOliver when I posted the question was tagged C++17 ... sorry about that. – Richard Critten Aug 15 '22 at 16:45
  • 1
    @ user17732522 The [dupe](https://stackoverflow.com/questions/71470692/struct-non-type-template-parameter-agregate-initialization-standard-in-c20) is related but does not answer this question because the dupe only says that *the grammar does not allow braced init list* but it does not says which exact grammar/clause/rule the user is talking about. Note also that this question is with`language-lawyer` unlike the dupe. – Jason Aug 16 '22 at 04:23

1 Answers1

2

GCC and MSVC are wrong in accepting the program as it is ill-formed for the reason explained below.

The standard doesn't allow braced init list {1,2,3,4} to be a template argument. This can be seen from temp.names#1:

template-argument:
    constant-expression
    type-id
    id-expression 

And since {1,2,3,4} is not any of the above three listed constructs, it cannot be used as a template argument.

Additionally note that {1,2,3,4} is not an expression and does not have a type.

This is the reason clang generates the error saying:

       vvvvvvvvvvvvvvvvvvv
error: expected expression
    constexpr Foo<Bar, {1,2,3,4}> foo;

The gcc bug has been reported as:

GCC accepts invalid program involving {1,2,3,4} as template argument

And msvc bug as:

MSVC accepts invalid program involving {1,2,3,4} as template argument

Jason
  • 36,170
  • 5
  • 26
  • 60
  • Are you sure `{1,2,3,4}` isn't covered by `constant-expression`? It doesn't seem to run afoul of any of the conditions [here](https://timsong-cpp.github.io/cppwp/expr.const#5) for a core constant expression. – NathanOliver Aug 15 '22 at 16:15
  • 1
    @NathanOliver `{1,2,3,4}` is not even an expression so i don't think it qualifies for a `constant expression`. Does it? – Jason Aug 15 '22 at 16:16
  • 4
    This is CWG2450; GCC/MSVC are simply preemptively allowing the syntax. – Davis Herring Aug 15 '22 at 16:19
  • Aha, looks like you need `type braced-init-list` in order for it to qualify as an expression. – NathanOliver Aug 15 '22 at 16:19
  • @DavisHerring Can you give a link to CWG2450 in your last comment? – Jason Aug 15 '22 at 16:20
  • @NathanOliver Yup, that will be the same as `new-type { expression-list(optional) }` as point 3 listed here: [Explicit type conversion](https://en.cppreference.com/w/cpp/language/explicit_cast) – Jason Aug 15 '22 at 16:23
  • 1
    Link to CWG2450: https://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2450 – NathanOliver Aug 15 '22 at 16:25