Search code examples
c++c++14language-lawyericctemplate-argument-deduction

Specifying only some template parameters at call time


Consider the short piece of variadic template code:

#include <type_traits>

template<int Dim, class... Idcs>
std::enable_if_t<sizeof...(Idcs) == 1> doit(Idcs... idcs)
{}

int main()
{
    doit<0>(1);
}

When I compile this using GCC/Clang, this compiles fine and Idcs is deduced as (int).

However, when I try to compile this using Intel's Compiler (version 18.0.0, 20170811), it for some reason thinks I'm manually specifying Idcs as an empty parameter pack, and then the enable_if_t fails.

The compiler error from icc:

myfile.cpp(9): error: no instance of function template "doit" matches the argument list
            argument types are: (int)
    doit<0>(1);
    ^
myfile.cpp(4): note: this candidate was rejected because there is a type mismatch after argument substitution
  std::enable_if_t<sizeof...(Idcs) == 1> doit(Idcs... idcs)
                                         ^

compilation aborted for myfile.cpp (code 2)

This can be fixed by changing the call inside of main() to specify all template parameters fully

doit<0, int>(1);

However, I would like to understand why the original code doesn't give the same result on all C++ 14 compilers. Is this something which is expected to compile successfully/unsuccessfully, or is this somehow undefined behavior, and why?

For reference, these are the commands I'm using to compile (on Linux, various versions/flavors):

g++ -std=c++14 myfile.cpp
clang++ -std=c++14 myfile.cpp
icc -std=c++14 myfile.cpp

Solution

  • This is most likely a bug in icc that was fixed in v19: https://godbolt.org/z/k1vbY9

    More investigation reveals that icc v18 (which does not compile your code) correctly deduces Idcs without enable_if: https://godbolt.org/z/WCZ_w8

    template<size_t Dim, class... Idcs>
    size_t doit(Idcs... idcs)
    {
        static_assert(sizeof...(Idcs) == 1);
        return sizeof... (Idcs);
    }
    
    auto test()
    {
        return doit<0>(1); // correctly returns 1 even on icc v18
    }