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
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
}