Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does this program violate the ODR?

Consider this program:

#include <type_traits>

template <typename T> constexpr bool g() { return true; }
template <typename T> std::enable_if_t< g<T>()> f() {}
template <typename T> std::enable_if_t<!g<T>()> f() {}

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

(Compiler Explorer)

It is acceptable to various versions of GCC and Clang, but it is not acceptable to MSVC, which fails to compile with the error message

1>D:\x.cpp(5,49): error C2995: 'enable_if<0,void>::type f(void)': function template has already been defined
1>D:\x.cpp(4): message : see declaration of 'f'
1>D:\x.cpp(4,49): error C3861: 'f': identifier not found

The first error message suggests an ODR violation to me - but if this program is ill-formed NDR, I need help understanding why that is so. I've checked [temp.over.link] in the standard draft, but I'm not confident that I'm interpreting it correctly. To my understanding the program is okay because these function templates have differing signatures.

In the unlikely case this program is correct, why does MSVC reject it?

like image 956
smiling_nameless Avatar asked Mar 22 '21 23:03

smiling_nameless


1 Answers

MSVC has a bug here.

For most functions, equivalence of arguments is sufficient to indicate an error. For templates, the return type expression is also involved.

MSVC seems to be ignoring the return type expression, and generating an error as if it could ignore it.

The g<T>()/!g<T>() part could be split into sizeof(T)==1 and sizeof(T)!=1 to remove one other confounding feature (the fact that one of those two cannot in practice be instantiated).

Try this:

template <typename T, std::enable_if_t<g<T>(),bool> =true> void f() {}
template <typename T, std::enable_if_t<!g<T>(),bool> =true> void f() {}

it will work in all 3 compilers.

like image 162
Yakk - Adam Nevraumont Avatar answered Oct 09 '22 06:10

Yakk - Adam Nevraumont