Search code examples
c++templatesvariadic-templatestemplate-argument-deduction

Variadic Template Specialization Overload works in GCC but not MSVC


I have the following function declarations

    template<typename RET, typename... PARAMS>
    RET Execute(PARAMS... params)
    { ... }
    
    template<typename RET>
    RET Execute()
    { ... }

    template<typename... PARAMS>
    void Execute(PARAMS... params)
    { ... }

    void Execute();

These calls work fine in both GCC and MSVC

    Execute<int32_t>(static_cast<int8_t>(0), static_cast<int32_t>(0))
    Execute<int32_t>()
    Execute(static_cast<uint8_t>(0))
    Execute()

This call works fine in GCC, but not in MSVC. I get an error for an ambiguous call to overload function. Just because the return type is the same as the first parameter.

    Execute<int32_t>(static_cast<int32_t>(0), static_cast<int32_t>(0))

Considering it is not possible to explicitly give the typenames of the parameter pack, it is not ambiguous. Why does MSVC seem to have this wrong? Is there anyway to fix this?


Solution

  • This call works fine in GCC, but not in MSVC.

    In my Debian stable, I get the same error also with clang++ 11.0.1-2 ("error: call to 'Execute' is ambiguous") and g++ 10.2.1 (" error: call of overloaded ‘Execute<int32_t>(int32_t, int32_t)’ is ambiguous").

    Considering it is not possible to explicitly give the typenames of the parameter pack

    Not exactly: you can explicit the typenames of the arguments or the types of the first arguments; this permit to overrides the typenames deduction from the arguments.

    Why does MSVC seem to have this wrong?

    My question is: why your g++ seems to have this right?

    Is there anyway to fix this?

    Yes, a very simple way: add a variadic list of non-types template parameter before the variadic list of the argument types.

    I mean, write the third Execute() as follows

    template <int..., typename... PARAMS>
    void Execute (PARAMS... params)
    { /* ... */ }
    

    and maybe also the first one as follows

    template <typename RET, int..., typename... PARAMS>
    RET Execute (PARAMS... params)
    { /* ... */ }
    

    This way you impose the PARAMS types deduction from the params and a explicit template parameter is necessarily the return type (when you can express it).