c++ - Template tricks with const char* as a non-type parameter -


i aware passing directly const char* template non-type parameter erroneous, since 2 identical string literals defined in 2 different translation units may have different addresses (although of time compilers use same address). there trick 1 may use, see code below:

#include <iostream>  template<const char* msg> void display() {     std::cout << msg << std::endl; }  // need have external linkage  // there no multiple definitions extern const char str1[] = "test 1"; // (1)  // why constexpr enough? have external linkage? constexpr char str2[] = "test 2";    // (2)  // why doesn't work?  extern const char* str3 = "test 3";  // (3) doesn't work  // using c_ptr_char = const char* const;   // (4) doesn't work either extern constexpr c_ptr_char str4 = "test 4";   int main() {     display<str1>();    // (1')     display<str2>();    // (2')     // display<str3>(); // (3') doesn't compile      //display<str4>();  // (4') doesn't compile } 

basically in (1) declare , define array external linkage, can used template parameter in (1'). understand well. however, don't understand:

  1. why constexpr version (2) works? constexpr have external linkage? if not, defining same string literal in different translation unit may lead duplicate template instantiation.

  2. why (3) , (4) don't work? seems reasonable me, compiler doesn't believe so:

    error: 'str3' not valid template argument because 'str3' variable, not address of variable

1. short answer: works irrespective of being declared constexpr, because you're defining object static storage duration (that not string literal - stores copy of contents of one), , address constant expression. regarding linkage, str2 has internal linkage, that's fine - address can used non-type template argument.

long answer:

in c++11 , 14, [14.3.2p1] says following:

a template-argument non-type, non-template template-parameter shall 1 of:
[...]

  • a constant expression (5.19) designates address of complete object static storage duration , external or internal linkage or function external or internal linkage, including function templates , function template-ids excluding non-static class members, expressed (ignoring parentheses) & id-expression, id-expression name of object or function, except & may omitted if name refers function or array , shall omitted if corresponding template-parameter reference;

[...]

so, can use address of object static storage duration, object has identified name linkage (internal or external), , way you're expressing address restricted. (string literals not names , don't have linkage.)

in short, char str1[] = "test 1"; works. static char str1[] = "test 1"; fine well; gcc 5.1.0 rejects it, think that's bug; clang 3.6.0 accepts it.


about str2's linkage, c++11 , 14 [3.5p3] says:

a name having namespace scope (3.3.6) has internal linkage if name of
[...]

  • a non-volatile variable explicitly declared const or constexpr , neither explicitly declared extern nor declared have external linkage;

[...]

n4431 has changed slightly, result of dr 1686, to:

  • a variable of non-volatile const-qualified type neither explicitly declared extern nor declared have external linkage;

reflecting fact constexpr implies const-qualification objects.


2. short answer: c++11 , 14, see above; draft c++1z, str3 not constant expression, pointer not constexpr, , it's address of string literal. str4 constant, still address of string literal.

long answer:

in current working draft, n4431, constraints on non-type template arguments have been relaxed. [14.3.2p1] says:

a template-argument non-type template-parameter shall converted constant expression (5.20) of type of template-parameter. non-type template-parameter of reference or pointer type, value of constant expression shall not refer (or pointer type, shall not address of):

  • a subobject (1.8),
  • a temporary object (12.2),
  • a string literal (2.13.5),
  • the result of typeid expression (5.2.8), or
  • a predefined __func__ variable (8.4.1).

and restrictions. converted constant expression part pretty important; full definition long, 1 part relevant our case address of object static storage duration such expression.

also relevant that, according [5.20p2.7], an lvalue-to-rvalue conversion applied

a non-volatile glvalue refers non-volatile object defined constexpr, or refers non-mutable sub-object of such object

also satisfies conditions being constant expression. allows use constexpr pointer variables non-type template arguments. (note declaring variable const not enough, can initialized non-constant expression.)

so, constexpr const char* str3 = str1; fine. it's accepted clang 3.6.0 in c++1z mode (and rejected in c++14 mode); gcc 5.1.0 still rejects - looks hasn't implemented updated rules yet.


still, what's wrong string literals? here's problem (n4431 [2.13.5p16]):

evaluating string-literal results in string literal object static storage duration, initialized given characters specified above. whether string literals distinct (that is, stored in nonoverlapping objects) , whether successive evaluations of string-literal yield same or different object unspecified.

an implementation allowed lots of things string literals: mix, match, make them overlap (entirely or partially), make 7 copies same translation unit - whatever. makes address of string literal unusable non-type template argument.


Comments

Popular posts from this blog

python - TypeError: start must be a integer -

c# - DevExpress RepositoryItemComboBox BackColor property ignored -

django - Creating multiple model instances in DRF3 -