简体   繁体   中英

c++ static int def in doubly nested template class fails with clang++ and g++

With following code:

struct my_symbols {
  enum class syms { symb_0_0, symb_0_1 };
};
template
< typename SymbolEnums
>
struct outer {
  using syms_0 = typename SymbolEnums ::syms;
  template <syms_0 AnSym0, int Int>
  struct inner {
    static int const val;
  };
};

template 
< typename SymbolEnums
>
template 
< typename outer<SymbolEnums>::syms_0 AnSym0
, int Int
>
int const outer<SymbolEnums>::inner<AnSym0, Int>::val = Int;

int main() {
  return 
      outer<my_symbols>::
      inner<my_symbols::syms::symb_0_1, 1>::val;
}

I get, with gcc5.2.0:

template definition of non-template 'int outer_tmpl::inner_tmpl::val' val=Int; ^

and with clang3.8.0, I get:

nested name specifier 'outer_tmpl::inner_tmpl::' for declaration does not refer into a class, class template or class template partial specialization val=Int; ^

How can I correct the code?

TIA.

I do not know exactly why the posted code does not work. I suspect the answer lies deep within the C++ Standard name lookup rules, which are incredibly complicated -- assuming, of course, that this is not actually a compiler bug. Someone else here probably knows.

The following "equivalent" examples compile on GCC 5.2.0 and Clang 3.8. They may or may not be suitable for your situation.

Example 1: Use constexpr and in-class initialization

struct my_symbols {
  enum class syms { symb_0_0, symb_0_1 };
};

template<typename SymbolEnums>
struct outer {

  using syms_0 = typename SymbolEnums::syms;

  template <syms_0 AnSym0, int Int>
  struct inner {
    static constexpr int val = Int;
  };
};

int main() {
  return outer<my_symbols>::inner<my_symbols::syms::symb_0_1, 1>::val;
}

Example 2: Tweak the nested template type parameter

struct my_symbols {
  enum class syms { symb_0_0, symb_0_1 };
};

template<typename SymbolEnums>
struct outer {

  using syms_0 = typename SymbolEnums::syms;

  template <syms_0 AnSym0, int Int>
  struct inner {
    static int const val;
  };
};

template<typename SymbolEnums>
template<typename SymbolEnums::syms AnSym0, int Int>
//       ^^^^^^^^^^^^^^^^^^^^^^^^^^
int const outer<SymbolEnums>::inner<AnSym0, Int>::val = Int;

int main() {
  return outer<my_symbols>::inner<my_symbols::syms::symb_0_1, 1>::val;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM