The short answer is: nothing in the standard changed – two non‐type template arguments of reference (or pointer) type are considered identical if they refer to the same entity, and so your partial specialization should be chosen in every C++ mode (myQuestion == 2). GCC has always done the “right” thing here; both clang (and by inheritance MSVC) in C++17 mode are simply non-conforming. A bug report against LLVM (and one against MSVC) is already open.
––––––––––––––––––––––––––––––––––––––––––––––
Why it must be 2 in all standards
From C++17 (N4659) [temp.arg.nontype] p8 (numbering in your draft may differ by one paragraph):
“Two template-arguments for a non-type template-parameter are equivalent if they are equal after conversion to the type of the template-parameter.
– for integral or enumeration types, they compare by value,
– for pointers or pointers-to-member, they compare by the address they hold,
– for reference types, they compare by the address of the object or function to which they refer.”
That same wording is present, un-changed, in C++11, C++14, C++17 and C++20. Since in
int i = 123;
const int which = Probe<int&, i, i>::which;
both non-type parameters n1 and n2 are references bound to the same object i, they are by definition equivalent, and so the partial specialization
template<class T, T n>
struct Probe<T, n, n> { static const int which = 2; };
must be picked.
––––––––––––––––––––––––––––––––––––––––––––––
What you see in the compilers
2 for both C++14 and C++17.2 in C++14 mode but mysteriously fall back to the primary template (1) in C++17 mode.The compilers are mis-implementing the reference-equality rule in C++17 mode. Bug reports have been filed in LLVM’s tracker and in the Visual Studio developer community.
Was this answer helpful?
version: o4-mini-2025-04-16
Status: UQ Validated
Validated: 8 months ago
Status: Needs Human Verification
Loading model reviews...
Loading reviews...