uray uray - 1 month ago 15
C++ Question

template function specialization default argument

template <typename T> void function(T arg1,
T min = std::numeric_limits<T>::min(),
T max = std::numeric_limits<T>::max())
{
}

template <> void function<int>(int arg1, int min,int max)
{
}

int main(int argc,char* argv[])
{
function<int>(1);
}


it give syntax error C2689 and C2059 on function default argument line on
::
token.
but without specialization, it doing fine. and if I change default argument
and still doing specialization:

template <typename T> void function(T arg1,
T min = T(0),
T max = T(1))
{
}
template <> void function<int>(int arg1, int min,int max)
{
}


the problem gone too.

now if I use it like this:
function<int>(1,2,3);
or
function<float>(1.0f)
its fine, so it seems that if template function is specialized, we must rewrite the default argument when call it?

but on my second case, where i replace
std::numeric_limits<T>::..
with
T(..)
there no syntax error when calling
function<int>(1)
, why is that?

(I'am using Visual Studio 2010 x64)

as original problem is because of bug, the question now changed to how to workaround it?

Answer

There is nothing wrong with the code; Comeau Online, Intel C++ 11.1, and g++ 4.1.2 compile it successfully.

I would guess that it is a bug in the compiler. I recently submitted a related, but slightly different bug report against the Visual C++ 2010 compiler.


As a workaround, you can wrap the calls:

template <typename T>
T get_limits_min() { return std::numeric_limits<T>::min(); }

template <typename T>
T get_limits_max() { return std::numeric_limits<T>::max(); }

template <typename T> void function(T arg1, 
    T min = get_limits_min<T>(),
    T max = get_limits_max<T>())
{
}

Ugly? Quite.


I posted the following in response to the bug you reported on Microsoft Connect:

The primary template must have a parameter that has a default argument value. The default argument value must be a member function of a class template not in the global namespace.

The following is minimal code to reproduce:

namespace N
{
    template <typename T>
    struct S
    {
        static T g() { return T(); }
    };
}

template <typename T> void f(T = N::S<T>::g()) { }

template <> void f<>(int) { }

int main()
{
    f<int>();
}

The compiler emits the following errors, both on the line where the primary template is defined:

error C2589: '::' : illegal token on right side of '::'
error C2059: syntax error : '::'

Interestingly, there is another issue if the class template is in the global namespace. Given the following code:

template <typename T>
struct S
{
    static T g() { return T(); }
};

template <typename T> void f(T = ::S<T>::g()) { }

template <> void f<>(int) { }

int main()
{
    f<int>();
}

The compiler emits the following error on the line on which the primary template is defined:

error C2064: term does not evaluate to a function taking 0 arguments

Both of these example test cases are well-formed C++ programs.