Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

static_assert with SFINAE

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)

like image 373
user11923373 Avatar asked Jan 19 '21 17:01

user11923373


People also ask

What is static assertion in C++?

The C++ 11 standard introduced a feature named static_assert() which can be used to test a software assertion at the compile time. Syntax : static_assert( constant_expression, string_literal ); Parameters : constant_expression : An integral constant expression that can be converted to a Boolean.

Should I use SFINAE or static_assert in C++?

Where applicable, tag dispatch, if constexpr (since C++17), and concepts (since C++20) are usually preferred over use of SFINAE. static_assert is usually preferred over SFINAE if only a conditional compile time error is wanted.

What is the size passed to static assert 2?

The size passed to it is ‘2’, which fails the condition to be checked, therefore producing the compile time error, and thus halting the compilation process. What are the advantages of static_assert over #error?

What is the scope of the static assert keyword?

(The static_assert keyword is technically a declaration, even though it does not introduce new name into your program, because it can be used at namespace scope.) In the following example, the static_assert declaration has namespace scope. Because the compiler knows the size of type void *, the expression is evaluated immediately.


1 Answers

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.

like image 77
StoryTeller - Unslander Monica Avatar answered Oct 23 '22 04:10

StoryTeller - Unslander Monica