In C++11, should the operation of static_assert within a template depend on whether that template has been instantiated or not? For example, with the following code
template <int I>
void sa() { static_assert(0,"Hello."); }
int main(int argc, char *argv[]) { return 0; }
GCC 4.5.0 will fail the assertion, and produce the "Hello." message.
The Digital Mars Compiler version 8.42n on the other hand, gives no message.
GCC is correct and the other compiler is correct too. Refer to 14.6p8 in the spec
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.
Therefor, a compiler is free to reject the following
template<typename T>
void f() {
static_assert(0, "may trigger immediately!");
static_assert(sizeof(T) == 0, "may trigger immediately!");
}
If you want to go safe, you have to arrange it so the compiler cannot know until instantiation whether the boolean expression will be true or false. For example, get the value by getvalue<T>::value, with getvalue being a class template (one could specialize it, so the compiler cannot possibly know the boolean value already).
I believe that the compiler is well within it's rights to expand any static assertions that are not dependent on template parameters without needing an instantiation- but I don't believe this is required. Remember also that different draft Standards may have different rules about when this may occur.
The C++0x draft (N3242) says in 14.6p8:
"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."
The same words appear in the C++03 standard.
In the case of the example from the question, no valid instantiation can be made for this template, so the quoted wording applies.
Since no diagnostic is required, the compiler may compile the program if the template is not instantiated. Of course, if it is instantiated then the program is ill-formed, with a diagnostic required.
I used a helper function to make the false dependent on the template parameter:
template<typename T>
bool dependentFalse<T>()
{
return false;
}
template<typename T>
Foo foo()
{
static_assert(dependentFalse<T>(), "this template shouldn't be instantiated");
}
This is 14.6.2 section in C++ standard.
Your static_assert is related to support binding nondependent names when initially parsing a template. The Digital Mars Compiler does not currently support binding nondependent names. GCC 4.5.0 does support binding nondependent names.
If your expression does not depend on the template parameters then such expression is known when initially parsing a template. Compiler must show the error message. GCC 4.5.0 does it.
Replace your 0 in static_assert with I*I < 0, for expample and you get dependent name. Error message will appear for the case of uninstantiated template only.
Related
I was playing around with C++ concepts and function overloading in a context completely removed from any templates, and stumbled upon this:
struct S
{
int mult(int x) requires (true) { return x; }
int mult(int x) requires (false) { return x * 2; }
};
int main()
{
std::cout << S{}.mult(5) << std::endl;
}
g++ 11 refuses to compile this snippet because requires-clauses may not be attached to non-template functions.
clang++ 13 is, however, fine with this snippet, but surprisingly spits out 10 instead of the 5 that I expected.
I know that the C++20 standard has only recently come out of the oven, so I completely understand that there are many issues to be worked out regarding concepts.
Disregarding the apparent uselessness of constant literal concepts, my question is: Are programs with requires-clauses which are always false ill-formed, possibly without requiring a diagnostic? Or, perhaps, is what I have not even legal C++ at all, as g++ is saying?
These are the two first examples in the "trailing requires-clause" section of the standard:
void f1(int a) requires true; // error: non-templated function
template<typename T>
auto f2(T a) -> bool requires true; // OK
Although examples given in the standard are explicitly non-normative, these make the intent abundantly clear.
Essentially, concepts can only be applied to template functions (so your code is invalid C++), but Boolean literals (e.g., requires true) are perfectly valid.
However, templates whose requirements are never satisfied (whether by a literal false in a required clause or otherwise) seem to be ill-formed, as indicated by this example,
Your snippet is not legal C++.
[dcl.decl.general]
4 The optional requires-clause ([temp.pre]) in an init-declarator or member-declarator shall be present only if the declarator declares a templated function ([dcl.fct]). When present after a declarator, the requires-clause is called the trailing requires-clause. [...]
Since there isn't a template in sight (and no room to discuss if the mult overloads are templated functions), your attempt is plain ill-formed. It's a "shall" requirement of a diagnosable rule.
So GCC is correct. Clang is doubly wrong to call a completely unintuitive overload. Though it really went of the rails when it accepted the program to being with.
As n. 1.8e9-where's-my-share m.'s answer says, concepts can only be used with templates. So your example is ill-formed.
What if a requires-clause which are always false appears in a template? According to [temp.res.general]/6.1:
The program is ill-formed, no diagnostic required, if:
no valid specialization can be generated for a template or a
substatement of a constexpr if statement within a template and the
template is not instantiated, or ...
It is still ill-formed, but no diagnostic required. Example 11 in [temp.res.general] also confirms this.
[Example 11:
template<typename T> struct S1 {
template<typename U>
requires false
struct Inner1; // ill-formed, no diagnostic required
};
template<typename T> struct S2 {
template<typename U>
requires (sizeof(T[-(int)sizeof(T)]) > 1)
struct Inner2; // ill-formed, no diagnostic required
};
The class S1<T>::Inner1 is ill-formed, no diagnostic required,
because it has no valid specializations. S2 is ill-formed, no
diagnostic required, since no substitution into the constraints of its
Inner2 template would result in a valid expression. — end example]
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)
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.
Consider the following template:
template <typename T>
void foo() {
static_assert(sizeof(T) == 0, "Now what?");
}
The standard (§7.4) says:
[If the condition to static_assert is false] the program is ill-formed, and the resulting diagnostic message (1.4) shall include
the text of the string-literal, […]
(Reference taken from https://stackoverflow.com/a/11048906/560450)
In practice, the static_assert will not fail until we instantiate the function template foo, because the use othe the template parameter forces the compiler to evalute the condition only during two-phase lookup. Therefore, the code snippet above is not deemed ill-formed unless the function template is instantiated.
On the other hand, sizeof(T) > 0 in C++ by definition. Therefore, the value of the condition is in fact independent of any template parameter! Is a "malicious" compiler allowed to take advantage of this fact, and reject the program as ill-formed, regardless whether foo is actually instantiated or not?
Yes, the compiler is allowed, but not required, to reject this.
§14.6 [temp.res]/p8:
If no valid specialization can be generated for a template, and that
template is not instantiated, the template is ill-formed, no
diagnostic required.
An easy workaround:
template <typename T>
struct foo_protector : std::false_type {};
template <typename T>
void foo() {
static_assert(foo_protector<T>::value, "Now what?");
}
The compiler is not allowed to reject foo()'s definition because there might be a specialization of foo_protector, not yet seen, such that its value member is true. As long as you don't actually write such a specialization, the static_assert will fire as expected.
I have a problem with this code snippet:
template <typename T>
struct S
{
static int a;
};
template <typename T>
decltype(S<T>::a) S<T>::a;
clang-3.4 says:
s.cpp:8:25: error: redefinition of 'a' with a different type: 'decltype(S<T>::a)' vs 'int'
decltype(S<T>::a) S<T>::a;
^
s.cpp:4:14: note: previous definition is here
static int a;
^
1 error generated.
But gcc-4.8.2 accepts. Which of the compilers is right? Should I avoid such code in the future?
Clang is demanding that the definition match the declaration at template definition time, whereas GCC and others defer matching until instantiation time (which never even happens for your example).
Clang accepts this:
#include <type_traits>
template <typename T>
struct S
{
static int a;
};
template <typename T>
typename std::enable_if< true, int >::type S<T>::a; // Resolves before instantiation
but rejects this small change:
template <typename T>
typename std::enable_if< std::is_same< T, T >::value, int >::type S<T>::a;
I cannot recall where the standard dictates when object declaration matching occurs, but I suspect that Clang is within its rights to reject the code. The intent of the standard, if I recall correctly, is that each declaration matches exactly one definition, and that mapping may be determined before instantiation time.
With the looser rule that GCC is apparently applying, you could have two member declarations and two definitions, but each definition may finalize either of the declarations depending on the template parameters.
The code which GCC and MSVC are accepting is ill-formed, no diagnosis required… pending finding the actual standardese buried somewhere in §3 [basic], §7 [dcl.dcl], §8 [dcl.decl], §14 [temp], or maybe somewhere else.
I still cannot find what rule matches object definitions to preceding declarations, but §14.4/2 dictates that decltype(…) cannot be the equivalent (I assume in the declarative sense) to int.
If an expression e involves a template parameter, decltype(e)
denotes a unique dependent type. Two such decltype-specifiers refer
to the same type only if their expressions are equivalent (14.5.6.1).
[Note: however, it may be aliased, e.g., by a typedef-name. — end
note ]
I'm pretty sure that equivalence, not mere aliasing, is necessary for the definition to match the declaration. §14.5.6.1 delves pretty deep into this territory, except it is specifically discussing function signatures.
I think Clang might be right in rejecting this. 14.2p2 says about decltype(e)
If an expression e involves a template parameter, decltype(e) denotes a unique dependent type.
In DR #2, the discussion trace says
My opinion (which I think matches several posted on the reflector recently) is that the out-of-class definition must match the declaration in the template.
...
In general, if you can match the declarations up using only information from the template, then the declaration is valid.
I think it still matches if one of them uses a typedef (as demonstrated in the DR), because S<T>::type is a member of the current instantiation and the type aliased can be looked up directly. But a decltype(e), as specified above, will always denote a unique type (during template parse time) except with respect to another decltype(e) that specifies an equivalent expression.
Why did I say might? Because of 14.6p8
No diagnostic shall be issued for a template for which a valid specialization can be generated.
One could read this as saying the type equivalence check is simply delayed till after instantiation. This, however, would contradict the discussion trace in the DR I think, because they say "if you can match the declarations up using only information from the template, then the declaration is valid" (and I assume the author of this statement meant to be exhaustive about the situations when the declaration is valid).
For me clang is broken here.
All combinations with decltype will fail. Without decltype it works.
template <typename T>
struct S
{
static int a;
using type = decltype( a );
typedef decltype( a ) type2;
};
template <typename T>
1) decltype(S<T>::a) S<T>::a;
2) int S<T>::a;
3) typename S<T>::type S<T>::a;
4) typename S<T>::type2 S<T>::a;
1 gcc works, clang fails
2 gcc + clang works
3 gcc works, clang fails
4 gcc works, clang fails
I did some more tries to work around the problem, but could not have any success.
There are some more discussions on that kind of problems:
C++ Static member initalization (template fun inside)
Edit:
I found that this topic is simply "not resolved" in the standard until now and clang did not implemented it:
Take a look at:
http://clang.llvm.org/cxx_dr_status.html ( point 205 )
I hope that I did not misunderstood the page. Feel free to correct my interpretation.
In C++11, should the operation of static_assert within a template depend on whether that template has been instantiated or not? For example, with the following code
template <int I>
void sa() { static_assert(0,"Hello."); }
int main(int argc, char *argv[]) { return 0; }
GCC 4.5.0 will fail the assertion, and produce the "Hello." message.
The Digital Mars Compiler version 8.42n on the other hand, gives no message.
GCC is correct and the other compiler is correct too. Refer to 14.6p8 in the spec
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.
Therefor, a compiler is free to reject the following
template<typename T>
void f() {
static_assert(0, "may trigger immediately!");
static_assert(sizeof(T) == 0, "may trigger immediately!");
}
If you want to go safe, you have to arrange it so the compiler cannot know until instantiation whether the boolean expression will be true or false. For example, get the value by getvalue<T>::value, with getvalue being a class template (one could specialize it, so the compiler cannot possibly know the boolean value already).
I believe that the compiler is well within it's rights to expand any static assertions that are not dependent on template parameters without needing an instantiation- but I don't believe this is required. Remember also that different draft Standards may have different rules about when this may occur.
The C++0x draft (N3242) says in 14.6p8:
"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."
The same words appear in the C++03 standard.
In the case of the example from the question, no valid instantiation can be made for this template, so the quoted wording applies.
Since no diagnostic is required, the compiler may compile the program if the template is not instantiated. Of course, if it is instantiated then the program is ill-formed, with a diagnostic required.
I used a helper function to make the false dependent on the template parameter:
template<typename T>
bool dependentFalse<T>()
{
return false;
}
template<typename T>
Foo foo()
{
static_assert(dependentFalse<T>(), "this template shouldn't be instantiated");
}
This is 14.6.2 section in C++ standard.
Your static_assert is related to support binding nondependent names when initially parsing a template. The Digital Mars Compiler does not currently support binding nondependent names. GCC 4.5.0 does support binding nondependent names.
If your expression does not depend on the template parameters then such expression is known when initially parsing a template. Compiler must show the error message. GCC 4.5.0 does it.
Replace your 0 in static_assert with I*I < 0, for expample and you get dependent name. Error message will appear for the case of uninstantiated template only.