Cómo declarar constexpr extern?


¿Es posible declarar una variable extern constexpr y definirla en otro archivo?

Lo intenté pero el compilador da error:

Declaración de constexpr variable 'i' no es una definición

In .h:

extern constexpr int i;

In .cpp:

constexpr int i = 10; 
Author: Ilya, 2015-05-13

4 answers

No, no puedes hacerlo, esto es lo que dice el estándar (sección 7.1.5):

1 El especificador constexpr se aplicará únicamente a la definición de un variable o plantilla variable, la declaración de una función o plantilla de función, o la declaración de un miembro de datos estáticos de una tipo literal (3.9). Si alguna declaración de una función, función plantilla, o plantilla variable tiene un especificador constexpr, entonces todos sus las declaraciones contendrán el especificador constexpr. [Nota: Un explícito la especialización puede diferir de la declaración de plantilla con respecto al especificador constexpr. No se pueden declarar los parámetros de la función constexpr. - nota final ]

Algunos ejemplos dados por el estándar:

  constexpr void square(int &x);  // OK: declaration
  constexpr int bufsz = 1024;  // OK: definition
  constexpr struct pixel {  // error: pixel is a type
    int x;
    int y;
    constexpr pixel(int);  // OK: declaration
  };

  extern constexpr int memsz; // error: not a definition
 14
Author: swang,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-05-13 07:56:17

No. Extern constexpr no tiene ningún sentido. Por favor, lea http://en.cppreference.com/w/cpp/language/constexpr

Es decir, el bit " se debe construir inmediatamente o asignarle un valor. "

 2
Author: Ed Heal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-05-13 07:48:11

Estoy de acuerdo con 'swang' arriba, pero hay una consecuencia. Considere:

ExternHeader.hpp

extern int e; // Must be extern and defined in .cpp otherwise it is a duplicate symbol.

ExternHeader.cpp

#include "ExternHeader.hpp"
int e = 0;

ConstexprHeader.hpp

int constexpr c = 0; // Must be defined in header since constexpr must be initialized.

Incluido1.hpp

void print1();

Incluido1.cpp

#include "Include1.hpp"
#include "ExternHeader.hpp"
#include "ConstexprHeader.hpp"
#include <iostream>

void print1() {
    std::cout << "1: extern = " << &e << ", constexpr = " << &c << "\n";
}

Incluido2.hpp

void print2();

Incluido2.cpp

#include "Include2.hpp"
#include "ExternHeader.hpp"
#include "ConstexprHeader.hpp"
#include <iostream>

void print2() {
    std::cout << "2: extern = " << &e << ", constexpr = " << &c << "\n";
}

Main.cpp

#include <iostream>
#include "Include1.hpp"
#include "Include2.hpp"

int main(int argc, const char * argv[]) {
    print1();
    print2();
    return 0;
}

Que imprime:

1: extern = 0x1000020a8, constexpr = 0x100001ed0
2: extern = 0x1000020a8, constexpr = 0x100001ed4

ES decir, el constexpr se asigna dos veces, mientras que el extern se asigna una vez. Esto es contradictorio para mí, ya que 'espero' constexpr estar más optimizado que extern.

Editar: const y constexpr tienen el mismo comportamiento, con respecto a la asignación, por lo tanto, desde ese punto de vista, el comportamiento es el esperado. Sin embargo, como he dicho, me sorprendió cuando me encontré con el comportamiento de constexpr.

 1
Author: Howard Lovatt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-12-02 05:03:28

algo es...

//===================================================================
// afile.h

#ifndef AFILE
#define AFILE

#include <cstddef>
#include <iostream>

enum class IDs {

  id1,
  id2,
  id3,
  END

};

// This is the extern declaration of a **constexpr**, use simply **const**
extern const int ids[std::size_t(IDs::END)];

// These functions will demonstrate its usage

template<int id> void Foo() { std::cout << "I am " << id << std::endl; }

extern void Bar();

#endif // AFILE

//===================================================================
// afile.cpp

#include "afile.h"

// Here we define the consexpr. 
// It is **constexpr** in this unit and **const** in all other units
constexpr int ids[std::size_t(IDs::END)] = {

  int(IDs::id1),
  int(IDs::id2),
  int(IDs::id3)

};

// The Bar function demonstrates that ids is really constexpr
void Bar() {

  Foo<ids[0]      >();
  Foo<ids[1] + 123>();
  Foo<ids[2] / 2  >();

}

//===================================================================
// bfile.h

#ifndef BFILE
#define BFILE

// These functions will demonstrate usage of constexpr ids in an extern unit

extern void Baz();
extern void Qux();


#endif // BFILE

//===================================================================
// bfile.cpp

#include "afile.h"

// Baz demonstrates that ids is (or works as) an extern field
void Baz() {

  for (int i: ids) std::cout << i << ", ";
  std::cout << std::endl;

}

// Qux demonstrates that extern ids cannot work as constexpr, though
void Qux() {

#if 0 // changing me to non-0 gives you a compile-time error...

  Foo<ids[0]>();

#endif

  std::cout << "Qux: 'I don't see ids as consexpr, indeed.'" 
            << std::endl;

}

//===================================================================
// main.cpp

#include "afile.h"
#include "bfile.h"

int main(int , char **)
{

  Bar();
  Baz();
  Qux();

  return 0;
}
 0
Author: PavDub,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-10 09:33:32