Consider the following code:
template <typename T> int foo();
template <typename T> int foo() = delete;
is this valid C++11?
GCC (9.1) says: Yes!
clang (8.0) says: No!
nvcc (9.2) says: No!
MSVC (19.20) says: Yes! (in C++14 mode, it doesn't support C++11.)
... see it all on GodBolt.
so which compilers are right and which compilers are s##$%e ? :-)
GCC and MSVC have a bug.
[dcl.fct.def.delete]
4 ... A deleted definition of a function shall be the first declaration of the function or, for an explicit specialization of a function template, the first declaration of that specialization...
Which I believe stands for instantiated declarations and definitions too. Since referring to a deleted function is a hard error, it must be declared as deleted asap.
Related
Another question of type "who's right between g++ and clang++?" for C++ standard gurus.
The following code
template <int>
struct foo
{
template <typename>
friend void bar ()
{ }
};
int main ()
{
foo<0> f0;
foo<1> f1;
}
compile without problem with clang++ (only two "unused variable" warnings) but give a the following error
tmp_002-11,14,gcc,clang.cpp: In instantiation of ‘struct foo<1>’:
tmp_002-11,14,gcc,clang.cpp:27:12: required from here
tmp_002-11,14,gcc,clang.cpp:20:16: error: redefinition of ‘template<class> void bar()’
friend void bar ()
^~~
tmp_002-11,14,gcc,clang.cpp:20:16: note: ‘template<class> void bar()’ previously defined here
compiling with g++.
The question, as usual, is: who's right ? g++ or clang++ ?
Checked with clang++ 3.9.1 and g++ 6.3.0 in my Debian platform. But, trying in Wandbox, seems equals with more recent versions.
GCC is right in this case.
The relevant standard wording is in [temp.inst]/2:
The implicit instantiation of a class template specialization causes
— the implicit instantiation of the declarations, but not of the
definitions, of the non-deleted class member functions, member
classes, scoped member enumerations, static data members, member
templates, and friends; and
[...]
However, for the purpose of
determining whether an instantiated redeclaration is valid according
to 6.2 and 12.2, a declaration that corresponds to a definition in the
template is considered to be a definition. [ Example: [...]
template<typename T> struct Friendly {
template<typename U> friend int f(U) { return sizeof(T); }
};
Friendly<char> fc;
Friendly<float> ff; // ill-formed: produces second definition of f(U)
— end example ]
The parts related to friends were added to this paragraph by DR2174 and published in C++17 (it's a defect report, so compilers should apply it to previous standard versions as well).
Recent versions of MSVC and EDG in strict mode also reject the code, complaining about a redefinition.
[temp.inject]/1 is somewhat related, but it only talks about friend functions, not friend function templates:
Friend classes or functions can be declared within a class template.
When a template is instantiated, the names of its friends are treated
as if the specialization had been explicitly declared at its point of
instantiation.
Compiler Fights XIV: Doom of the Duplicitous Double Definition, co-starring The Dubious Declaration!
Compilers, all with either -O0 or Debug mode:
g++ 5.2.0
clang++ 3.6.0
VC++ 18.00.40629 (MSVC 2013, Update 5)
Summary:
Is VC++ wrong in rejecting the declaration and definition of a specialized static member variable of a templated class with the syntax?
template <> const std::string TemplatedClass::x; // .h file
template <> const std::string TemplatedClass::x= "string"; // .cpp file
Does removing the declaration in the header file cause an otherwise well-defined program to be ill-formed?
If so, is there a VC++ friendly way to declare the specialization of a static member variable of a templated class?
While making an MCVE of a problem I was having with defining specialized static member variables of a template, I encountered an interesting variation in behavior between VC++, GCC and Clang with respect to the declaration said specialized static member variables. Specifically, the syntax
template <> const std::string TemplatedClass<int>::x; // .h file
template <> const std::string TemplatedClass<int>::x= "string"; // .cpp file
seems to mortally offend VC++, which responds with complaints of multiple definitions:
error C2374: 'member' : redefinition; multiple initialization
while both gcc and clang take this in stride.
Research
I'm assuming the latter two are correct because they usually are, and also because the above syntax is from an answer regarding static member initialization of a specialized template class, which quotes paragraph 14.7.3/15 from the standard of 2010 in stating that template<> X Q<int>::x is a declaration, not a definition. I took the liberty of tracking down the equivalent paragraph of draft N4296, thinking it could have changed in the intervening time. It has, but only in that it's moved two paragraphs up and contains additional clarification:
14.7.3/13
An explicit specialization of a static data member of a template or an explicit specialization of a static data member template is a definition if the declaration includes an initializer; otherwise, it is a declaration.
[ Note: The definition of a static data member of a template that requires default initialization must use a braced-init-list:
template<> X Q<int>::x; // declaration
template<> X Q<int>::x (); // error: declares a function
template<> X Q<int>::x { }; // definition
— end note ]
This seems pretty clear to me, but VC++ seems to have a different interpretation. I've tried simply commenting out the offending declaration, and no compilers complain, which would seem to solve my troubles, but doesn't because paragraph 6 has this to say: (worrying emphasis mine)
14.7.3/6
If a template, a member template or a member of a class template is explicitly specialized then that specialization shall be declared before the first use of that specialization that would cause an implicit instantiation to take place, in every translation unit in which such a use occurs; no diagnostic is required. If the program does not provide a definition for an explicit specialization and either the specialization is used in a way that would cause an implicit instantiation to take place or the member is a virtual member function, the program is ill-formed, no diagnostic required. An implicit instantiation is never generated for an explicit specialization that is declared but not defined.
It provides examples, but all of them are for specializing functions after they're used or specializing member enums and classes of a templated type, which I'm fairly certain don't apply to this problem. However, the initial words of p13 seem to imply that the declaration of the specialized static member variable is also an explicit specialization, at least when using the illustrated syntax.
MCVE
The test I used for my experimentation can be found on Coliru, with apologies to StackedCrooked for the fairly involved command line. A much shortened version is below:
main.cpp
#include <iostream>
// 'header' file
#include "test.h"
int main(){
std::cout << test::FruitNames<Fruit::APPLE>::lowercaseName();
}
test.h (declaration not commented out)
test.h (declaration commented out)
#ifndef TEMPLATE_TEST
#define TEMPLATE_TEST
#include <algorithm>
#include <locale>
#include <string>
namespace test{
enum class Fruits{
APPLE
};
template <Fruits FruitType_>
class FruitNames{
static const std::string name_;
/*...*/
public:
static std::string lowercaseName() {/*...uses name_...*/}
};
// should be counted as declaration. VC++ doesn't.
template <> const std::string FruitNames<Fruits::APPLE>::name_;
} // end namespace test
#endif // TEMPLATE_TEST
test.cpp
#include "test.h"
namespace test{
template <> const std::string FruitNames<Fruits::APPLE>::name_ = "Apple";
}
Output
Both gcc and clang will output
apple
with or without the specialization declaration in test.h. VC++ will do so if the declaration in test.h is commented out, but will produce a double initialization error if it is present.
Finally
Is VC++ incorrect to reject the declaration/explicit specialization syntax for the static member variable of a templated class as previously stated, or is it an allowed but not mandatory diagnostic error?
Does the removal of the declaration cause the program to be
ill-formed?
If it is ill formed without the declaration, how do I get VC++ to play nice with a
well-defined program?
Is VC++ incorrect to reject the declaration/explicit specialization syntax for the static member variable of a templated class as previously stated, or is it an allowed but not mandatory diagnostic error?
Yes, this is a bug in VC++. It has apparently been fixed in Visual Studio 2019 version 16.5 Preview 2.
Does the removal of the declaration cause the program to be ill-formed?
Your quote from the standard seems to suggest that. Other people agree.
If it is ill formed without the declaration, how do I get VC++ to play nice with a well-defined program?
As a workaround, you can specialize the whole class and then define the member without the template<> syntax. See Amir Kirsh's answer to a similar question:
https://stackoverflow.com/a/58583521/758345
Alternatively, you could define and initialize your variable in your header and mark it as inline (since c++17):
template <> inline const std::string TemplatedClass::x = "string"; // .h file
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).
If a normal function calls a function that has not been declared yet, I get a compile-time error:
void foo(int x)
{
bar(x); // ERROR: bar has not been declared yet
}
void bar(int x)
{
std::cout << x << '\n';
}
int main()
{
foo(42);
}
The fix is to either forward-declare the called function, or to switch the order of definitions.
However, these fixes do not seem to be necessary with function templates:
template<typename T>
void foo(T x)
{
bar(x); // OKAY
}
template<typename T>
void bar(T x)
{
std::cout << x << '\n';
}
int main()
{
foo(42);
}
This compiles just fine. Why is that? When the compiler sees bar(x), why does it not complain?
(I am using g++ 4.6.3)
This is a "why is the sky made out of bricks" type question. Ie, a question that asks why something false is true. It is not the case that in C++ your code is legal.
Live example, as you can see in gcc 4.8 this does not actually compile.
I guess the question "why does gcc 4.6 let this code compile" remains. One of the things that compilers did early on when writing template expanders was to treat them as something similar to macros. Very little would be done when they where declared, and everything would be looked up when they where instantiated.
Compilers now tend to do more thing when the template is declared, and less when it is instantiated. This is what the C++ standard requires, or is at least closer.
As it happens, ADL can get around this: bar lookups that find bar via ADL do not have to be visible at the point where foo is written, but rather at the point of instantiation.
The gcc 4.8 error message is pretty self explanatory:
prog.cpp: In instantiation of ‘void foo(T) [with T = int]’:
prog.cpp:16:7: required from here
prog.cpp:6:10: error: ‘bar’ was not declared in this scope, and no declarations were found by argument-dependent lookup at the point of instantiation [-fpermissive]
bar(x); // OKAY
^
prog.cpp:10:6: note: ‘template<class T> void bar(T)’ declared here, later in the translation unit
void bar(T x)
^
these requirements may have been changed or clarified in C++11, so it is possible that gcc 4.6's behavior was legal under the C++03 standard.
When the compiler first sees bar(x), it doesn't know x's type, hence it can't look up the correct bar. Only when you instantiate foo, T and therefore x's type are known and bar(x) can be looked up.
Note that this work only for dependent expression, i.e. expressions that depend on a template parameter. If you add bar(42), it will fail to compile even if it is later instantiated with T==int.
You might also want to google "two-phase lookup" for further information. Only recent versions of GCC implement those rules correctly, as some checks also need to be done during the first phase of parsing the template. As pointer out by Yakk, newer versions of GCC reject your code, so always check with up-to-date versions of GCC or Clang to be on the safe side.
A function template isn't a function; it's a recipe for making functions, once the template parameters are known.
The compiler can't look up what bar means when it sees the foo template definition, because what it means could depend on what T is. So it just remembers that there's a use of the name bar that will need to be worked out later.
When you call foo(42) the compile has to produce (instantiate) the real function, and at that point it looks up the names it wasn't able to before, finds your bar template (and triggers instantiation of that too) and all is well.
For a normal function all names can be looked up when the function is defined, and so they must be properly declared at that point.
With "non-dependent" here I mean "non-dependent on any other template arguments of that specific function template".
While answering this question, I thought I found the answer, but according to #Johannes (in the comments to my answer), I'm misinterpreting the standard here. Take the following simple example:
#include <type_traits>
template<class T>
struct X{
template<class U = typename T::type>
static void foo(int){}
static void foo(...){}
};
int main(){
X<std::enable_if<false>>::foo(0);
}
(Live version.)
Is there any guarantee that the above compiles? GCC and Clang disagree here, as can be seen in the live version when switching between them. Interestingly, though, the following is accepted by GCC:
#include <type_traits>
template<class T>
struct X{
template<bool = T::f()>
static void foo(int){}
static void foo(...){}
};
struct Y{
static bool f(){ return true; }
};
int main(){
X<Y>::foo(0);
}
(Live version.)
The second snippet will only print foo(int) if T contains a constexpr static function f. Again, interestingly, if you completely remove f from Y (or pass, say, int instead), GCC complains about a missing member, indicating that it doesn't allow for SFINAE - which is contradictory with the previous observation. Clang takes all variations and applies SFINAE, and I wonder if that's what is guaranteed by the standard.
(FWIW, MSVC with the Nov CTP generally agrees with Clang, but crashes on the second snippet if the function is present, likely because they don't have constexpr. I submitted a bug report here.)
I think the code in question is incorrect, as when the class template is instantiated, all member declarations are instantiated, except the definition parts and default arguments of the member functions and member function templates. The Standard also defines when the function default arguments are instantiated precisely.
So default template-arguments are immediately instantiated. The possibility that default arguments could be intended to include default template arguments at this point is very small here in my opinion, because there is no description of when such an argument would be instantiated later.
This is in line with the requirement that "A default template-argument shall not be specified in the template-parameter-lists of the definition of a member of a class template that appears outside of the member's class.", since there would be no way that such a template argument be instantiated immediately when instantiating the surrounding class template.