compiler problems with variable template - c++

The following code (taken from Wikipedia) defines the variable template pi<>:
template<typename T=double>
constexpr T pi = T(3.14159265358979323846264338328);
template<>
constexpr const char* pi<const char*> = "π";
With the clang compiler (Apple clang version 12.0.0) (with C++14), this triggers a warning (with -Weverything):
no previous extern declaration for non-static variable 'pi<const char *>'
declare 'static' if the variable is not intended to be used outside of this translation unit
Moreover, since this was defined in a header, multiple instances of 'myNameSpace::pi<char const*>' were created, causing linker errors.
So, as suggested, I added the static keyword, which silenced the warning:
template<>
static constexpr const char* pi<const char*> = "π";
But now gcc (9.3.0) is unhappy, giving an error pointing at the static keyword:
error: explicit template specialization cannot have a storage class
What is the correct way to avoid either warning and error?

The warning from (this old version of) Clang is partly misleading, but does indicate the real problem that you eventually encountered with the linker. The warning describes the good rule of thumb that a global variable ought to
appear with extern in a header and then without in a source file, or
appear with static in a source file (avoiding collisions with any other symbol).
The latter choice doesn't apply to explicit specializations: since linkage applies to templates as a whole (the standard says that it pertains to the name of the template, which is evocative even if it doesn't work well for overloaded functions), you can't make just one specialization static and Clang is incorrect to accept it. (MSVC also incorrectly accepts this.) The only way to make a "file-local specialization" is to use a template argument that is a local type, template, or object. You can of course make the whole variable template have internal linkage with static or an unnamed namespace.
However, the former choice does apply: an explicit specialization is not a template, so it must be defined exactly once (in a source file). Like any other global variable, you use extern to reduce the definition to a declaration:
// pi.hh (excerpt)
template<typename T=double>
constexpr T pi = T(3.14159265358979323846264338328);
template<>
extern constexpr const char* pi<const char*>;
// pi.cc
#include"pi.hh"
template<>
constexpr const char* pi<const char*> = "π";
(Since the primary template is, well, a template, it is defined in the header file.)
As mentioned in the comments, C++17 allows inline variables; your explicit specialization again behaves like an ordinary global variable and can be defined with inline in a header if desired.

Related

How to define a constexpr constructed array that will have only one instance over many translation units?

I'm generating an constexpr std::array inside of a constexpr class, but I only want one instance of that class over all of the project where it is used.
I had originally made it a global, but then I found out that these globals are duplicated if I iterate over the array in multiple translation units. I then attempted to use a constexpr function, but I can't have a static inside of such a function. I'm using c++14, so I can't use an inline constexpr variable. An extern constexpr variable doesn't make sense because if you separate the declaration from the definition, then how can the constexpr values be dealt with in a compile time rather than a runtime manner when only one item is needed?
Are there any other options?
EDIT: See https://godbolt.org/z/5PcboYov4
Please remember that I'm not defining a regular variable. I'm defining a constexpr variable. The difference is IMPORTANT. It is being used in both non-constexpr and constexpr contexts.
Variable templates have external linkage, even if they are const-qualified:
template<typename = void>
constexpr std::array my_array{/*...*/};
// use my_array<> to access the array.
This is however only since DR 2387, which I guess should also apply to C++14 although it was resolved only in 2019.
If the compiler does not implement it, then you can add extern explicitly. As far as I can tell that is allowed and the declaration will still be a definition because it has an initializer. Because it is a template, there is no ODR violation for multiple definitions:
template<typename = void>
extern constexpr std::array my_array{/*...*/};
// use my_array<> to access the array.
For some reason I forgot the most obvious workaround using a static data member:
struct my_array_wrapper {
static constexpr std::array</*...*/> my_array{/*...*/};
};
// in one translation unit
constexpr std::array</*...*/> my_array_wrapper::my_array;
Then my_array_wrapper::my_array can be used. The definition in the translation unit is required if the array is ODR-used before C++17 only. Static data members in a class with external linkage also have external linkage, regardless of whether they are const-qualified.

Why is constexpr solving duplicated definition?

I have a header file where string are defined as static global.
namespace space {
#define NAME(P) static std::string const s_##P = #P
NAME(foo); NAME(bar); //... other values
#undef NAME
}
In another header, an enum is defined and a template specialization provides the mapping between the enum and a string in space.
enum class letter { alpha, beta };
template<letter> std::string const & mapping();
#define MAPPING(P1,P2) template<> std::string const & mapping<letter::P1>() { return space::s_##P2; }
MAPPING(alpha,foo)
MAPPING(beta,bar)
#undef MAPPING
The above code doesn't link when the header is included in more than one translation unit because the specializations definitions do not match - due to global redefinition per translation unit (I guess).
Wrapping the mapping functions in anonymous namespace or adding static keyword solves the linking issue but then the compiler complains that the functions are defined but not used [-Wunused-function].
template<letter> static std::string const & mapping();
But, defining the specializations as constexpr, there is no longer any link or warning issue.
template<letter> std::string const & mapping();
#define MAPPING(P1,P2) template<> constexpr std::string const & mapping<letter::P1>() { return space::s_##P2; }
I understand why the non-static version fails at link time and why the static version works and triggers warnings. But I don't understand why the constexpr specifier solves both issues.
Can you please give an explanation and even better, a rational in the standard ?
Function template specializations are functions, and are therefore subject to the one-definition rule in the same manner as functions that are not template specializations.
The linker errors you saw when the functions were declared neither static nor constexpr were due to multiple definitions of the same function template specializations which each had external linkage.
When you added static, you made the linkage internal. This made it safe for each translation unit to contain its own copy of the definitions. However, in any TU in which those functions were not called, the compiler knew that (due to internal linkage) they could not be called from any other TU either, making them unused.
With constexpr, the functions become inline implicitly according to the standard, but their linkage is not affected. Since they are inline, you can have multiple definitions, but since they have external linkage, the compiler does not complain when one TU does not use them.
functions declared with the constexpr specifier are inline functions.
From the C++ 20 Standard (9.2.5 The constexpr and consteval specifiers)
1 The constexpr specifier shall be applied only to the definition of a
variable or variable template or the declaration of a function or
function template. The consteval specifier shall be applied only to
the declaration of a function or function template. A function or
static data member declared with the constexpr or consteval specifier
is implicitly an inline function or variable (

Difference between constexpr and static constexpr global variable

In the C++11 standard, what is the difference between constexpr and static constexpr global variables when defined in a header? More specifically, when multiple translation units include the same header, which declaration (if any) is guaranteed to define the same variable across the translation units?
e.g.,
cexpr.h:
#ifndef CEXPR_H
#define CEXPR_H
constexpr int cint = 1;
static constexpr int scint = 1;
#endif
a.cpp:
#include "cexpr.h"
b.cpp:
#include "cexpr.h"
In your current example there is no difference: On variable declarations, constexpr implies const, and a const variable at namespace scope has internal linkage by default (so adding static does not change anything).
In C++14, you cannot declare a variable as constexpr and have it have external linkage unless you only ever do this in one single translation unit. The reason is that constexpr variables require an initializer, and a declaration with initializer is a definition, and you must only have a single definition.
However, what you can do is use a normal integral constant, which you can declare (not define) as extern, and in the translation unit where it is defined it can even be used as a constant expression:
lib.h:
extern const int a;
lib.cpp:
#include "lib.h"
const int a = 10;
int b[a] = {1, 2, 3}; // OK in this translation unit
In C++17, there is a new feature "inline variables" which lets you say:
inline constexpr int a = 10;
And this is an "inline definition" that can appear repeatedly, and each definition defines the same entity (just like all the other "inline" entities in the language).
I think this article explains more clear. 6.8 — Global constants and inline variables
Because const globals have internal linkage, each .cpp file gets an independent version of the global variable that the linker can’t see. In most cases, because these are const, the compiler will simply optimize the variables away.
The term “optimizing away” refers to any process where the compiler optimizes the performance of your program by removing things in a way that doesn’t affect the output of your program. For example, lets say you have some const variable x that’s initialized to value 4. Wherever your code references variable x, the compiler can just replace x with 4 (since x is const, we know it won’t ever change to a different value) and avoid having to create and initialize a variable altogether.
So, the "cint " and "scint" are all internal linkage variables.
The best practice to define global variable after C++ 17:
inline constexpr double pi = 0;
Working Mechanism:
C++17 introduced a new concept called inline variables. In C++, the term inline has evolved to mean “multiple definitions are allowed”. Thus, an inline variable is one that is allowed to be defined in multiple files without violating the one definition rule. Inline global variables have external linkage by default.
Inline variables have two primary restrictions that must be obeyed:
1) All definitions of the inline variable must be identical (otherwise, undefined behavior will result).
2) The inline variable definition (not a forward declaration) must be present in any file that uses the variable.
The compiler will consolidate all inline definitions into a single variable definition. This allows us to define variables in a header file and have them treated as if there was only one definition in a .cpp file somewhere. These variables also retain their constexpr-ness in all files in which they are included.
If you can, prefer the static constexpr because with the constexpr it depends on the toolchain how likely it will get done on compile-time. Gcc is most aggressive, MSVS least aggressive and clang is in between.
Instead of leaving some values up to optimizer to decide it will do it at compile-time be more explicit and force it.
Reference:
https://www.youtube.com/watch?v=4pKtPWcl1Go

Why does the following method get internal linkage?

I'm using clang-3.6 and compiling a sizeable project. After a massive re-factoring, a small number of seemingly random methods in a few classes cause warnings such as this:
warning: function 'namespace::X::do_something' has internal linkage but is not defined [-Wundefined-internal]
The same functions also show up as missing in the linker stage.
Here is the anonymized header for one such function definition in X.hpp:
class X {
// ...
void do_something(
foo::Foo& foo,
double a
double b,
double c,
uint8_t d,
const bar::Bar& bar,
int dw, int dh);
// ...
}
The function is implemented in X.cpp as normal. When Y.cpp includes X.hpp and does x->do_something, the warning about internal linkage appears.
How can a method defined as above have internal linkage? What are all the circumstances under which a method gets internal linkage?
And seeing as this function, and others, used to compile just fine and have not even been touched during the refactoring, what kind of side effects (include order, type Foo and Bar) can cause a method to switch to internal linkage?
EDIT:
When I do a full source grep of do_something, it gives three results:
X.hpp: void do_something(
X.cpp: void X::do_something(
Y.cpp: x->do_something(
I also tried to change the name of do_something into a long guaranteed unique name to rule out any possibility of name conflicts.
As far as I can tell, the posted method definition is unquestionably the one being flagged as having internal linkage.
It was due to one of the types (i.e. foo:Foo) being a template type where one of the template parameters had erroneously gotten internal linkage.
template <typename char const* Name> struct Foo{...};
const char constexpr FooBarName[] = "Bar";
using FooBar = Foo<FooBarName>;
The presence of FooBar in any argument list or as a return type would give that method internal linkage. Not even clang-3.8 with -Weverything complained about having a template parameter with internal linkage.
The obvious fix was to properly use extern const char for the template string parameter.

Resolving Definitions of Specialized Static Member Variables of Templated Classes

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