Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Template template class with enum specification fails on MSVC++ Compiler: C3201

Code

Here is the SSCCE example of my problem:

// My Library, which I want to take in the user's enum and a template class which they put per-enum specialized code
template <typename TEnum, template <TEnum> class EnumStruct>
struct LibraryT { /* Library stuff */ };

// User Defined Enum and Associated Template (which gets specialized later)
namespace MyEnum {
    enum Enum {
        Value1 /*, ... */
    };
};

template <MyEnum::Enum>
struct MyEnumTemplate {};

template <>
struct MyEnumTemplate<MyEnum::Value1> { /* specialized code here */ };

// Then the user wants to use the library:
typedef LibraryT<MyEnum::Enum, MyEnumTemplate> MyLibrary;

int main() {
    MyLibrary library;
}

[EDIT: Changing LibraryT<MyEnum::Enum, MyEnumTemplate> to LibraryT<typename MyEnum::Enum, MyEnumTemplate> has no effect]

Error

The functionality I desire is the ability to create a library based on an enum and a class which is specialized by that enum. Above is my first attempt. I believe it is 100% C++, and GCC backs me up and says it all works. However, I want it to compile with the MSVC++ Compiler and it refuses:

error C3201: the template parameter list for class template 'MyEnumTemplate' 
  does not match the template parameter list for template parameter 'EnumStruct'

Question

Is there some way I can make the MSVC++ compiler [EDIT: MSVC++ 11 Compiler (VS 2012)] like my code? Either by some addition specifications or different approach?

Possible (but undesirable) Solution

Hard code the enum type to be some integral type (the underlying type). Then no problems. But then my library is operating on integrals instead of the enum type (undesirable, but working)

// My Library, which I want to take in the user's enum and a template class which they put per-enum specialized code
typedef unsigned long IntegralType; // **ADDED**

template <template <IntegralType> class EnumStruct> // **CHANGED**
struct LibraryT { /* Library stuff */ };

// User Defined Enum and Associated Template (which gets specialized later)
namespace MyEnum {
    enum Enum {
        Value1 /*, ... */
    };
};

template <IntegralType> // **CHANGED**
struct MyEnumTemplate {};

template <>
struct MyEnumTemplate<MyEnum::Value1> {};

// Then the user wants to use the library:
typedef LibraryT<MyEnumTemplate> MyLibrary; // **CHANGED**

int main() {
    MyLibrary library;
}
like image 727
Bob Fincheimer Avatar asked Oct 04 '12 19:10

Bob Fincheimer


1 Answers

This is a known bug in the Visual C++ compiler. See the following bug on Microsoft Connect for more information (the repro is slightly different, but the issue is effectively the same):

C++ compiler bug - cannot use template parameters inside nested template declaration

The recommended workaround is to use an integer type for the template parameter of the template template parameter, which is what you have done in your "possible (but undesirable) solution."

like image 121
James McNellis Avatar answered Oct 10 '22 23:10

James McNellis