11

The standard says in [temp.res]/8:

No diagnostic shall be issued for a template definition for which a valid specialization can be generated. If no valid specialization can be generated for a template definition, and that template is not instantiated, the template definition is ill-formed, no diagnostic required. ... [ Note: If a template is instantiated, errors will be diagnosed according to the other rules in this Standard. Exactly when these errors are diagnosed is a quality of implementation issue. — end note ]

My question is: Does the following count as a valid specialization that can be generated?

#include <type_traits>

template <typename T, typename Enable = void>
class A;

template <typename T>
class A<T, typename std::enable_if<not std::is_same<T, int>::value>::type>
{
public:
    static_assert(std::is_same<T, int>::value, "should not be here!");
};

On the one hand, the static_assert essentially amounts to a static_assert(false, "should not be here"); (we can't both not be an int and be an int at the same time), which isn't allowed. On the other hand, as far as SFINAE is concerned, the type, e.g., A<double> is perfectly well formed and can be generated, but will immediately throw a static assertion failure. This currently works in GCC 8.3, but given the "ill-formed, no diagnostic required" part of the standards quote above, I want to make sure that it actually should work. (Note: work here is defined to mean it throws a static assertion failed if I try to instantiate a A<double> and compiles silently if I don't)

user11923373
  • 471
  • 1
  • 11

1 Answers1

5

No, it's not meant to work. That is not a valid C++ program.

Per the very paragraph you cite, the template definition of your partial specialization is ill-formed NDR. There is no valid specialization that may be generated from it.

The standard typically designates something as ill-formed NDR because checking it reliably in the general case would amount to contradicting Rice's theorem. So compilers aren't obligated to try, but they may try some heuristic analysis or other.

GCC and Clang often diagnose more as heuristics are added to them. I wouldn't try to claim "this is dependent" as a shield against that. The code itself is invalid from the get-go.

StoryTeller - Unslander Monica
  • 148,497
  • 21
  • 320
  • 399
  • I guess I may have been confused as to what was meant by "generating" a valid specialization - if it was just enough to pass SFINAE, or if it meant there was actually a valid type that could be allowed to be instantiated. Your answer (as well as your comment on the answer above that some compilers reject `sizeof(T) == 0`) appear to indicate that it is the former, and not the latter. – user11923373 Jan 19 '21 at 17:46
  • 1
    @user11923373 - The normative text refers to a *template-definition* intentionally. I.e, the blueprint of the actual class we are generating. The spirit of [temp.res]/8 is about guarding against blueprints that cannot ever produce something valid. The SFINAE is a bit of a red herring. Because when it fails, we don't get a valid specialization from *that* template definition. And when it passes, we still get something invalid. – StoryTeller - Unslander Monica Jan 19 '21 at 17:50