Michael Doubez
Michael Doubez

Reputation: 6903

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 ?

Upvotes: 2

Views: 768

Answers (2)

Vlad from Moscow
Vlad from Moscow

Reputation: 311088

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 (

Upvotes: 1

Brian Bi
Brian Bi

Reputation: 119467

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.

Upvotes: 4

Related Questions