Home > Blockchain >  Is it an ODR violation to have an inline templated function have different behavior due to if conste
Is it an ODR violation to have an inline templated function have different behavior due to if conste

Time:04-12

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.

  • Related