paulm
paulm

Reputation: 5892

Why won't this template compile?

I have the following class used with MSVC2013 Update 4:

template <typename T>
class MyFunction;

template<typename R, class... Ts>
class MyFunction < R(Ts...) >
{
public:
    using func_type = R(*)(Ts...);

    MyFunction(func_type f)
        : m_func(f)
    {
    }

    R operator()(Ts ... args)
    {
        return m_func(args...);
    }

private:
    func_type m_func;
};

If I use it like so:

MyFunction<int (int)> f1(nullptr);
MyFunction<int __cdecl(int)> f2(nullptr);
MyFunction<int __stdcall(int)> f3(nullptr);

Why does f3 fail to compile? (Considering that __cdecl works!).

error C2079: 'f3' uses undefined class 'MyFunction<int (int)>'  
error C2440: 'initializing' : cannot convert from 'nullptr' to 'int'    

Upvotes: 0

Views: 88

Answers (1)

T.C.
T.C.

Reputation: 137315

In MSVC, the calling convention is part of the function type; the default calling convention is __cdecl, so R(Ts...) is really R __cdecl (Ts...) and doesn't match int __stdcall(int).

If you compile with /Gz, which makes the default calling convention __stdcall, you'd see an error on f2 instead.

You'll have to write partial specializations for all calling conventions you want to support:

template<class F, class R, class... Args>
class MyFunctionImpl {
public:
    using func_type = F*;

    MyFunctionImpl(func_type f)
        : m_func(f)
    {
    }

    R operator()(Args ... args)
    {
        return m_func(args...);
    }

private:
    func_type m_func;
};

template<typename R, class... Ts>
class MyFunction < R __cdecl(Ts...) >
    : MyFunctionImpl<R __cdecl(Ts...), R, Ts...> {
    using MyFunctionImpl<R __cdecl(Ts...), R, Ts...>::MyFunctionImpl;
};

template<typename R, class... Ts>
class MyFunction < R __stdcall(Ts...) >
    : MyFunctionImpl<R __stdcall(Ts...), R, Ts...> {
    using MyFunctionImpl<R __stdcall(Ts...), R, Ts...>::MyFunctionImpl;
};

// etc.

Upvotes: 2

Related Questions