It's possible to detect if a type is complete https://devblogs.microsoft.com/oldnewthing/20190710-00/?p=102678
I have reason to want to provide a different (inlinable) implementation if a type is complete.
Is it an ORD violation for a templated function to behave differently in different translation units based on an if constexpr
in the function? In a sense, it's the "same" function in the different translation units (it's not macros creating different definitions at a C source level, which is an ODR violation).
Here's a simple example:
#include <iostream>
#include <type_traits>
// From https://devblogs.microsoft.com/oldnewthing/20190710-00/?p=102678
template<typename, typename = void>
constexpr bool is_type_complete_v = false;
template<typename T>
constexpr bool is_type_complete_v
<T, std::void_t<decltype(sizeof(T))>> = true;
template <typename T>
T* loggingGetRef(T* x) {
if constexpr (is_type_complete_v<T>) {
std::cout << "Complete!" << std::endl;
} else {
std::cout << "Incomplete!" << std::endl;
}
return x;
}
struct S
//{} // <- Uncomment this to make loggingGetRef be "different" through if constexpr.
;
int main() {
S* ptr = nullptr;
loggingGetRef(ptr);
}
https://godbolt.org/z/q1soa58PY
For my application, I would want the two if constexpr
branches to outwardly act the same (unlike this example that prints different things) so from a correctness standpoint, it would be OK if the linker picked the assembly for either implementation and used that everywhere. It's just that in a translation unit where T
is complete we may be able to get better performance (and I fully expect it to be inlined).
CodePudding user response:
ODR is not based on "templated functions"; it is based on actual functions. Templates generate functions based on template parameters. Each unique set of template parameters represents a different function. Different functions generated from the same template are different functions. There are no ODR expectations between different functions, regardless of what created them.
loggingGetRef<S>
is the name of a particular function. If you do something that causes loggingGetRef<S>
to generate differently due to constant expressions, you have ill-formed code (no diagnostic required). But that isn't a matter of ODR violations; that's a violation of the rules of template instantiation. A template that is instantiated with a specific set of parameters must be the same in all translation units that instantiate it with those parameters. Period.