I agree that this feature is missing - I need it too. Example:

double pow(double x, int n) {
    // calculate x to the power of n
    return ...
}

static inline double pow (double x, constexpr int n) {
    // a faster implementation is possible when n is a compile time constant
    return ...
}

double myfunction (double a, int b) {
    double x, y;
    x = pow(a, b);  // call version 1 unless b becomes a compile time constant by inlining
    y = pow(a, 5),  // call version 2
    return x + y;
}

Now I have to do this with templates:

template <int n>
static inline double pow (double x) {
    // fast implementation of x ^ n, with n a compile time constant
    return ...
}

This is fine, but I miss the overload opportunity. If I make a library function for others to use then it is inconvenient that the user has to use different function calls depending on whether n is a compile time constant or not, and it may be difficult to predict whether the compiler has reduced n to a compile time constant or not.


Edit: Trick described below is not guaranteed to work anymore!

Detecting constexpr can't be made using overloads (like others already replied) but overloads are just one way to do it.

The typical problem is that we can't use something that can improve run-time performance (for example to call non-constexpr functions or to cache results) in constexpr function. So we may end up with two different algorithms, one less efficient but writable as constexpr, other optimized to run fast but not constexpr. Then we want compiler not to choose the constexpr algorithm for run-time values and vice versa.

That can be achieved by detecting constexpr and selecting based on it "manually" and then shortening the interface down with preprocessor macros.

First lets have two functions. In general the functions should reach same result with different algorithms. I choose two algorithms that never give same answers here just to test and to illustrate the idea:

#include <iostream>     // handy for test I/O
#include <type_traits>  // handy for dealing with types

// run-time "foo" is always ultimate answer
int foo_runtime(int)
{
    return 42;
}

// compile-time "foo" is factorial
constexpr int foo_compiletime(int num)
{
      return num > 1 ? foo_compiletime(num - 1) * num : 1;
}

Then we need a way to detect that argument is compile time constant expression. If we don't want to use compiler-specific ways like __builtin_constant_p then there are ways to detect it in standard C++ as well. I'm pretty sure that following trick is invented by Johannes Schaub but I can't find the cite. Very nice and clear trick.

template<typename T> 
constexpr typename std::remove_reference<T>::type makeprval(T && t) 
{
    return t;
}

#define isprvalconstexpr(e) noexcept(makeprval(e))

The noexcept operator is required to work compile-time and so branching based on it will be optimized out by most compilers. So now we can write a "foo" macro that selects the algorithm based on argument's constexprness and to test it:

#define foo(X) (isprvalconstexpr(X)?foo_compiletime(X):foo_runtime(X))

int main(int argc, char *argv[])
{
    int a = 1;
    const int b = 2;
    constexpr int c = 3;
    const int d = argc;

    std::cout << foo(a) << std::endl;
    std::cout << foo(b) << std::endl;
    std::cout << foo(c) << std::endl;
    std::cout << foo(d) << std::endl;
}

Expected output is:

42
2
6
42

On the few compilers that I tried it works like expected.


It would have to be overloaded based on the result being constexpr or not, rather than the arguments.

A const std::string could store a pointer to the literal, knowing that it would never be written to (using const_cast to remove const from the std::string would be necessary, and that's already undefined behavior). It'd just be necessary to store a boolean flag to inhibit freeing the buffer during destruction.

But a non-const string, even if initialized from constexpr arguments, requires dynamic allocation, because a writable copy of the argument is required, and therefore a hypothetical constexpr constructor should not be used.


From the standard (section 7.1.6.1 [dcl.type.cv]), modifying any object which was created const is undefined behavior:

Except that any class member declared mutable (7.1.1) can be modified, any attempt to modify a const object during its lifetime (3.8) results in undefined behavior.