Search code examples
c++templatesgccconstexprauto

Conflicting declaration using constexpr and auto in C++11


I'm experimenting with C++11, constexpr and auto.

I'm failing to understand why this code does not compile:

  template<class T, T t>
  struct TestEle2
    {

    };

template<class T, T t>
  struct DStruct {int a;};

  template<char t>
  struct TestEle2<char, t>
    {
    static constexpr auto f = 5;

    static constexpr auto g = &DStruct<char, t>::a;
    };

  template<char c>
  constexpr decltype(TestEle2<char, c>::f)
    TestEle2<char, c>::f ; // This compiles

  template<char c>
  constexpr decltype(TestEle2<char, c>::g)
    TestEle2<char, c>::g ; // This does not compile

Without definition I have linking problems. I know this problem has been fixed in C++17 but better understand fully C++11 now

[Edit] Error message is:

error: conflicting declaration ‘constexpr decltype (TestEle2<char, t>::g) TestEle2<char, t>::g’
         TestEle2<char, c>::g ;
                            ^
error: ‘TestEle2<char, t>::g’ has a previous declaration as ‘constexpr const auto TestEle2<char, t>::g’
         static constexpr auto g = &DStruct<char, t>::a;
                               ^
error: declaration of ‘constexpr const auto TestEle2<char, t>::g’ outside of class is not definition [-fpermissive]

[Edit 2] I'm using GCC 4.8.5


Solution

  • Consider the following a long comment instead of an answer (sorry).

    I don't know who is right (MSVS that accept all, g++ that accept f but refuse g or clang++ that refuse both f and g) but, if I understand correctly, this is a simplification of a more complex problem that you can't solve simply using int and int * instead of auto.

    So I propose to insert a couple of types inside TestEle2

    using typeF = decltype(5);
    using typeG = decltype(&DStruct<char, t>::a);
    

    and use them instead of auto and decltype() for f and g types.

    The following is a full compiling (both g++ and c++; I don't know MSVS (sorry)) example

    template <class T, T t>
    struct TestEle2
     { };
    
    template <class T, T t>
    struct DStruct
     { int a; };
    
    template <char t>
    struct TestEle2<char, t>
     {
       using typeF = decltype(5);
       using typeG = decltype(&DStruct<char, t>::a);
    
       static constexpr typeF f = 5;
       static constexpr typeG g = &DStruct<char, t>::a;
     };
    
    // This compiles
    template <char c>
    constexpr typename TestEle2<char, c>::typeF TestEle2<char, c>::f; 
    
    // This also compile
    template <char c>
    constexpr typename TestEle2<char, c>::typeG TestEle2<char, c>::g;
    
    int main()
     {
     }