views:

102

answers:

2

The following code

#include <stdio.h>
template <typename T, T v> class Tem
{
    T t;
    Tem()
    {
        t = v;
    }
};

typedef Tem<FILE*,NULL> TemFile;

when compiled in a .mm file (Objective C++) by Xcode on MacOS X, throws the following error:

error: could not convert template argument '0' to 'FILE*'.

What's going on, please? The code in question compiled fine under MSVC. Since when is the 0 constant not a valid pointer to anything? Is this an artifact of Objective C++ (as opposed to vanilla C++)?

A: 

Did you try something like this?

typedef Tem<FILE*,((FILE*)NULL)> TemFile;

Perhaps it's trying to figure out the type of NULL.

Jay
That would throw a different error:a cast to a type other than an integral or an enumeration type cannot appear in a constant-expression
Seva Alekseyev
+1  A: 

According to the standard, you are out of luck. There is no way to initialize a pointer argument to anything besides the address-of a global. §14.3.2/1:

A template-argument for a non-type, non-template template-parameter shall be one of:

  • an integral constant-expression of integral or enumeration type; or
  • the name of a non-type template-parameter; or
  • the address of an object or function with external linkage, including function templates and function template-ids but excluding non-static class members, expressed as & id-expression where the & is optional if the name refers to a function or array, or if the corresponding template-parameter is a reference; or
  • a pointer to member expressed as described in 5.3.1 .

§14.3.2/5:

  • for a non-type template-parameter of type pointer to object, qualification conversions (4.4) and the array-to-pointer conversion (4.2) are applied. [Note: In particular, neither the null pointer conversion (4.10) nor the derived-to-base conversion (4.10) are applied. Although 0 is a valid template-argument for a non-type template-parameter of integral type, it is not a valid template-argument for a non-type template-parameter of pointer type. ]

However, Comeau accepts this invalid workaround:

typedef Tem<FILE*, (FILE *) NULL > TemFile;

And this code has a slim chance of compliance: I can't find where the standard specifically says that a default expression is used verbatim in place of a a missing argument, and I can't find a matching known defect. Anyone have a reference?

#include <stdio.h>
template <typename T, T *v = (T*) 0> class Tem
{
    T t;
    Tem()
    {
        t = v;
    }
};

typedef Tem<FILE> TemFile;

For more portability, you might consider creating a bogus FILE FILE_NULL;, pass &FILE_NULL, and test for pointer-equality with that instead of zero.

Potatoswatter
Comeau probably accepts it because it's valid C++0x.
Johannes Schaub - litb
@Johannes: Thanks, I missed the new bullet point they put that in and Comeau accepted it despite "turning off" C++0x.
Potatoswatter