themagicalyang
themagicalyang

Reputation: 2553

What is the deduced type of a constexpr?

#include <iostream>
#include <string>

void foo(int& k) { std::cout << "int&\n"; }
void foo(int&& k) { std::cout << "int&&\n"; }
void foo(const int& k) { std::cout << "const int&\n"; }
void foo(const int&& k) { std::cout << "const int&&\n"; }    
int main() {
  static  constexpr int k = 1;
  foo(k);
  foo(1);
}

The output is:

const int&
int&&

What exactly is a constexpr variable treated as? The overload for foo gives const int&.

Edit: Moving on with constexpr being deduced as const T&;

Why does a constexpr at class scope fail to be passed to a function taking universal reference?!

#include <type_traits>

template <typename T>
void goo(T&& k) {
  static_assert(std::is_same<decltype(k), const int&>::value, "k is const int&");
}

class F {
  static  constexpr int k = 1;
public:
  void kk2 () { goo(k); }
};

int main () {
  F a;
  a.kk2();
}

The above fails to compile giving error undefined reference to F::k However the below passes:

#include <type_traits>

template <typename T>
void goo(T&& k) {
  static_assert(std::is_same<decltype(k), const int&>::value, "k is const int&");
}

int main() {
  static  constexpr int k = 1;
  goo(k);
}

Upvotes: 8

Views: 337

Answers (2)

Oktalist
Oktalist

Reputation: 14714

foo(1);

In this case a temporary variable with the value 1 is passed to the function foo, hence non-const rvalue.

/*static*/ constexpr int k = 1;
foo(k);

Here a named const variable with the value 1 is passed to the function foo, hence const lvalue. The static keyword has no effect on a constexpr variable at function scope.

What exactly is a constexpr variable treated as?

When used in an expression that is not a constant expression, a constexpr variable is just a const variable.

Why does a constexpr at class scope fail to be passed to a function taking universal reference?!

You are getting a linker error because you odr-used the variable without defining it. You need a definition of F::k at namespace scope in exactly one translation unit, just like you did for static const member variables in C++98.

Upvotes: 1

TartanLlama
TartanLlama

Reputation: 65630

N3337 [dcl.constexpr]/9: A constexpr specifier used in an object declaration declares the object as const. [...]

Since you declared k as constexpr, it is also declared as const, so the const int& is selected in overload resolution.

Upvotes: 2

Related Questions