Why does the code below compile? I am not specializing a template member function of a template class, so only one template<> should be used. However, g++ compiles it with no warnings whatsoever, clang++ gives only a warning
warning: extraneous template parameter list in template
specialization
template<typename T>
struct S{};
template<> template<> // why can we do this?
struct S<int>{};
int main()
{
}
Because the grammar allows it, and there doesn't seem to be anything under the template specialization section that prohibits it:
From [gram.temp]
explicit-specialization:
template < > declaration
From [gram.dcl]
declaration:
[...]
explicit-specialization
The fact that the grammar is too lax has been in the active issues list (#293) since 2001.
A bug report (filed as PR5559) from a much older version of clang discusses the issue as well. The problem is that gcc and clang both have discrepancies when it comes to whether multiple template declarations are valid during an explicit specialization. Quoth Gabor Greif:
The first error is actually none, clang correctly diagnoses that only one "template <>" is needed. But because g++ accepts this and several people (like me) may have the misconception that the number of "template <>"s is governed by nesting instead of the number of levels being specialized, it may be interesting to reduce the error to a warning and possibly emit a fixit hint.
The disparity could also be caused by the standard's cyclic definition of an explicit specilization (as noted by #user657267).
Related
The following compiles without error in VS2019 (version 16.11.15) with C++ 17 selected as the language. But it fails with C++ 20 with error "error C2027: use of undefined type 'Anon'"
template <typename T> class a_template
{
public:
void do_something(class Anon& anon) const;
};
template <typename T> void a_template<T>::do_something(class Anon& anon) const
{
anon.do_something();
}
The Anon class is of course undefined but the ::do_something function is unused so does not need to be instantiated. This is OK in C++17 but apparently not in C++20.
Is this a change in language rules? If so, can it be fixed without actually defining Anon?
Is this a change in language rules?
No, this is due to the fact that a C++ compiler is permitted (but not required!) to diagnose errors at the time the template is parsed
when all of the instantiations of the template would produce that error.
This means that for your given example, at the time of parsing the definition compilers may or may not issue an error. That is, the compiler can produce an error when parsing the template or may wait until the first template instantiation. Refer to demo where msvc doesn't issue an error but gcc and clang does.
Perhaps a simpler example would make it more clear :
void func()
{
}
template<typename T> void bar()
{
func(3); //compilers are allowed(but not required) to issue error at the time of pasrsing this
}
In the above example, func is a nondependent name and at the point where we have called func using func(3), the only visible func is the one that accepts 0 arguments and not one. And as i said earlier, some compiler may issue an error(at the time of parsing) even though we've not instantiated bar but some compilers may not. This is because they are allowed to but not required to do so. See demo where msvc doesn't issue an error here but gcc and clang does.
The same logic applies to your example as well. Meaning as Anon is an incomplete type and you have anon.do_something(), some compiler might choose to produce an error even though you have not instantiated a_template and some other compiler might not.
A coworker shared this code with me:
run on gcc.godbolt.org
#include <iostream>
struct A
{
void foo() {std::cout << "1\n";}
template <typename T = int>
void foo() {std::cout << "2\n";}
};
int main()
{
A x;
x.template foo();
}
GCC prints 1, Clang prints 2, and MSVC complains about missing template arguments.
Which compiler is correct?
[temp.names]/5 says that a name prefixed by template must be a template-id, meaning that it must have a template argument list. (Or it can refer to a class/alias template without template argument list, but this is deprecated in the current draft as a result of P1787R6 authored by #DavisHerring.)
There is even an example almost identical to yours under it, identifying your use of template as ill-formed.
The requirement and example comes from CWG defect report 96, in which the possible ambiguity without the requirement is considered.
Open GCC bug report for this is here. I was not able to find a Clang bug report, but searching for it isn't that easy. Its implementation status page for defect reports however does list the defect report as unimplemented.
MSVC is correct to reject this: the standard has just this as an example. The template parser guide is allowed before the qualified name of a class or alias template without template arguments, but this is only for compatibility with implementations that needlessly require it for template template arguments and is now deprecated.
The following code compiles in Visual C++ 2013 but not under G++ 4.8.2:
template<class T>
int MyFunc(T& t)
{
return static_cast<int>(CCodes::blah);
}
template<>
int MyFunc(float& t)
{
return 0;
}
int main() {
float f = 10.f;
return MyFunc(f);
}
Visual C++ seems to ignore the general template function because only the specialisation MyFunc<float> is used. G++ parses the general function anyway and spots that the CCodes enumeration has not been defined.
Which is right? Or is this implementation-defined?
GCC is correct, and every other compiler besides MSVC will do the same thing.
This is a major bug, which actually appeared on one MSVC future roadmap. It was in the "distant future" category. They will have to rewrite their template engine to fix it.
There is a line of argument that diagnosis of an ill-formed template is optional, because it's really a template with no well-formed instantiation, and those are not required to be flagged. However,
The standard requires the template to be parsed, and failure to parse must be diagnosed regardless of instantiation.
Every other compiler makes the diagnosis, so in effect not doing so leads MSVC users to produce unportable code. Complaining is a really good idea, even if it's not required.
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.
This is more of a c++ standards question.
Consider the following code:
template <typename T>
class has_Data
{
typedef char one;
typedef long two;
template <typename C> static one test( typeof(&C::Data) ) ;
template <typename C> static two test(...);
public:
enum { value = sizeof(test<T>(0)) == sizeof(char) };
};
class MyClass {
private:
struct Data {
};
};
void function(bool val = has_Data<MyClass>::value) {}
The above code works with gcc (GCC) 4.4.3
However with clang version 3.3 (2545b1d99942080bac4a74cda92c620123d0d6e9) (2ff97832e593926ea8dbdd5fc5bcf367475638a9)
it gives this error:
test_private_data.cpp:7:54: error: 'Data' is a private member of 'MyClass'
template <typename C> static one test( typeof(&C::Data) ) ;
^
/devshared/home/rhanda/test_private_data.cpp:7:37: note: while substituting explicitly-specified template arguments into function template 'test'
template <typename C> static one test( typeof(&C::Data) ) ;
^
/devshared/home/rhanda/test_private_data.cpp:21:26: note: in instantiation of template class 'has_Data<MyClass>' requested here
void function(bool val = has_Data<MyClass>::value) {}
^
1 error generated.
Which one is right?
From standard document (n3485), I found a statement which seems to agree with clang more than gcc.
Access control is applied uniformly to all names, whether the names are referred to from declarations or expressions.
I would assume that GCC is right.
The first thing to note is that no non-friend code should be able to positively report the existence of a given private member. So if that is what you try to do, you have to modify your design. A class can do anything with its private members, and other code (excepting friends) should have no way to know about it. That's by design.
However, there is the SFINAE principle: substitution failure is not an error. Since MyClass::Data is private, the code in has_Data should – in my opinion – act as if there was no C::Data member at all. Hence the first function would lead to a substitution failure, which gets silently ignored, and the second function is the one used. Adding a bit more code, my GCC 4.7.2 compiles this without issues and with has_Data<MyClass>::value evaluating to false. Correct SFINAE in my opinion.
Trying to back this opinion up with a quotation from the document you referred to, I found the following in section 14.8.2 paragraph 8:
Note: Access checking is done as part of the substitution process.
This is a non-normative note in the standard, but to me appears to be a very readable and clear indication that SFINAE should in fact apply in this situation, just the way GCC handles it.
Edit: As #hvd pointed out in a comment, the above is only true for C++11. In older versions of the standard, the situation used to be different. Issue 1170: Access checking during template argument deduction has details on that change.
GCC will not compile this code with -std=c++03 or -std=c++11 due to the fact that typeof is a GNU extension. The fact that -std=gnu++03 still compiles the code might perhaps be considered inappropriate, but since the way forward is using the C++11 semantics, I wouldn't bother filing a report about this.