Constante integral pasada por valor, tratada como constexpr?
Aunque he usado código como este antes, y está claro que el compilador tiene suficiente información para funcionar, realmente no entiendo por qué esto compila:
template <class T, class I>
auto foo(const T& t, I i) {
return std::get<i>(t);
}
int main()
{
std::cerr << foo(std::make_tuple(3,4), std::integral_constant<std::size_t, 0>{});
return 0;
}
Ejemplo en vivo:http://coliru.stacked-crooked.com/a/fc9cc6b954912bc5.
Parece funcionar tanto con gcc como con clang. La cosa es que mientrasintegral_constant
tiene unconstexpr
conversión al entero almacenado,constexpr
Las funciones miembro toman implícitamente el objeto en sí mismo como argumento y, por lo tanto, dicha función no puede utilizarse en unconstexpr
contexto a menos que el objeto que estamos llamando la función miembro en sí mismo pueda ser tratado comoconstexpr
.
Aquí,i
es un argumento pasado afoo
, y por lo tantoi
ciertamente no puede ser tratado comoconstexpr
. Sin embargo, lo es. Un ejemplo aún más simple:
template <class I>
void foo(I i) {
constexpr std::size_t j = i;
}
Esto también se compila, siempre questd::integral_constant<std::size_t, 0>{}
se pasa afoo
.
Siento que me falta algo obvio sobre elconstexpr
reglas. ¿Existe una excepción para los tipos sin estado, o algo más? (o, tal vez, un error de compilación en dos compiladores principales? Este código parece funcionar en clang 5 y gcc 7.2).
Editar: se ha publicado una respuesta, pero no creo que sea suficiente. En particular, dada la última definición defoo
, por que:
foo(std::integral_constant<std::size_t, 0>{});
Compilar, pero no:
foo(0);
Tanto 0 comostd::integral_constant<std::size_t, 0>{}
son expresiones constantes
Edición 2: Parece que se reduce al hecho de que llamar a unconstexpr
La función miembro, incluso en un objeto que no es una expresión constante, puede considerarse como una expresión constante, siempre quethis
Está sin usar. Esto se toma como obvio. No considero esto obvio:
constexpr int foo(int x, int y) { return x; }
constexpr void bar(int y) { constexpr auto x = foo(0, y); }
Esto no se compila, porquey
como pasó afoo
No es una expresión constante. No se usa, no importa. Por lo tanto, una respuesta completa debe mostrar algún tipo de lenguaje del estándar para justificar el hecho de que unconstexpr
la función miembro se puede usar como una expresión constante, incluso en un objeto de expresión no constante, siempre quethis
Está sin usar.