Consider the following program (godbolt):
template <typename, typename>
struct is_same { static constexpr bool value = false; };
template <typename T>
struct is_same<T, T> { static constexpr bool value = true; };
template <typename T, typename U>
static constexpr bool is_same_v = is_same<T, U>::value;
using uintptr_t = unsigned long long;
template <int const* I>
struct Parameterized { int const* member; };
template <typename T>
auto create() {
static constexpr int const I = 2;
return Parameterized<&I>{ &I };
}
int main() {
auto one = create<short>();
auto two = create<int>();
if (is_same_v<decltype(one), decltype(two)>) {
return reinterpret_cast<uintptr_t>(one.member) == reinterpret_cast<uintptr_t>(two.member) ? 1 : 2;
}
return 0;
}
Based on n4659 (C++17 final working draft):
§ 17.4 [temp.type]/1:
Two template-ids refer to the same class, function, or variable if:
- their template-names, operator-function-ids, or literal-operator-ids refer to the same template and
- their corresponding type template-arguments are the same type and
- their corresponding non-type template arguments of integral or enumeration type have identical values and
- their corresponding non-type template-arguments of pointer type refer to the same object or function or are both the null pointer value and
- their corresponding non-type template-arguments of pointer-to-member type refer to the same class member or are both the null member pointer value and
- their corresponding non-type template-arguments of reference type refer to the same object or function and
- their corresponding template template-arguments refer to the same template.
I would expect that:
- Either there is a single instance of
static constexpr int const I = 2;for all instantiations ofcreate<T>, in which casedecltype(one)refers to the same class asdelctype(two). - Or there is one instance of
static constexpr int const I = 2;for each instantiation ofcreate<T>, in which case the two refer to a different class.
Yet, when using GCC or Clang (any version which produces a binary), the result of main is 2 indicating:
- The same class for both
oneandtwo. - Yet a different instance of
create<T>()::I.
The assembly listing confirms that 2 instances are created: _ZZ6createIsEDavE1I (aka create<short>()::I) and _ZZ6createIiEDavE1I (aka create<int>()::I).
According to the C++17 standard, should the types of one and two be the same, or not?
Interesting variation: replacing = 2 by = sizeof(T) results in the types being different (see godbolt).