Search code examples
genericsc++-cli

C++/CLI value class constraint won't compile. Why?


a few weeks ago a co-worker of mine spent about two hours finding out why this piece of C++/CLI code won't compile with Visual Studio 2008 (I just tested it with Visual Studio 2010... same story).

public ref class Test
{
    generic<class T> where T : value class
        void MyMethod(Nullable<T> nullable)
    {

    }
};

The compiler says: Error

1 error C3214: 'T' : invalid type argument for generic parameter 'T' of generic 'System::Nullable', does not meet constraint 'System::ValueType ^' C:\Users\Simon\Desktop\Projektdokumentation\GridLayoutPanel\Generics\Generics.cpp 11 1 Generics

Adding ValueType will make the code compile.

public ref class Test
{
    generic<class T> where T : value class, ValueType
        void MyMethod(Nullable<T> nullable)
    {

    }
};

My question is now. Why? What is the difference between value class and ValueType?

P.S: See the Nullable definition for C++: http://msdn.microsoft.com/de-de/library/b3h38hb0.aspx


Solution

  • I analyzed the IL code of the three following methods:

    generic<class T> where T : value class, System::ValueType
        static void MyMethod(T arg)
    {
    
    }
    
    generic<typename T> where T: value class
        static void MyMethod2(T arg)
    {
    
    }
    
    generic<typename T> where T: ValueType 
        static void MyMethod3(T arg)
    {
    }
    

    The corresponding IL-code, which I dissassembled with .NET-Reflector:

    .method public hidebysig 
     static void MyMethod<valuetype ([mscorlib]System.ValueType).ctor T>
    (!!T arg) cil managed
    {
    }
    
    
    .method public hidebysig 
    static void MyMethod2<valuetype .ctor T>(!!T arg) cil managed
    {
    }
    
    
    .method public hidebysig
    static void MyMethod3<([mscorlib]System.ValueType) T>(!!T arg) cil managed
    {
    }
    

    This is the IL-declaration of Nullable<T>:

    .class public sequential ansi serializable sealed beforefieldinit 
    Nullable<valuetype (System.ValueType) .ctor T>
        extends System.ValueType
    

    As you can clearly see, only the first method's constraint matches 100% with Nullable<T>'s. (Btw: value class seems to imply the presence of a standard constructor). However, why the compiler produces different IL-code for (semantically) the same constraints, remains still a mystery. I will ask Microsoft's C++/CLI Gurus for further information.