c++

Related: Function returning constexpr does not compile

I feel like constexpr is limited in usefulness in C++11 because of the inability to define two functions that would otherwise have the same signature, but have one be constexpr and the other not constexpr. In other words, it would be very helpful if I could have, for example, a constexpr std::string constructor that takes constexpr arguments only, and a non-constexpr std::string constructor for non-constexpr arguments. Another example would be a theoretically complicated function that could be made more efficient by using state. You can't easily do that with a constexpr function, so you are left with two choices: have a constexpr function that is very slow if you pass in non-constexpr arguments, or give up on constexpr entirely (or write two separate functions, but you may not know which version to call).

My question, therefore, is this:

Is it possible for a standard-compliant C++11 implementation to allow function overloading based on the arguments being constexpr, or would this require updating the standard? If it is not allowed, was it intentionally not allowed?


@NicolBolas: Say I have a function that maps an enum to a std::string . The most straight-forward way to do this, assuming my enum goes from 0 to n - 1 , is to create an array of size n filled with the result.

I could create a static constexpr char const * [] and construct a std::string on return (paying the cost of creating a std::string object every time I call the function), or I can create a static std::string const [] and return the value I look up, paying the cost of all of the std::string constructors the first time I call the function. It seems like a better solution would be to create the std::string in memory at compile time (similar to what is done now with char const * ), but the only way to do this would be to alert the constructor that it has constexpr arguments.

For a an example other than a std::string constructor, I think it's pretty straight-forward to find an example where, if you could ignore the requirements of constexpr (and thus create a non- constexpr function), you could create a more efficient function. Consider this thread: constexpr question, why do these two different programs run in such a different amount of time with g++?

If I call fib with a constexpr argument, I can't beat do better than the compiler optimizing away the function call entirely. But if I call fib with a non- constexpr argument, I may want to have it call my own version that implements things like memoization (which would require state) so I get run time similar to what would have been my compile time had I passed a constexpr argument.


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.


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.


Detecting and using constexpr can't be made with overloads like others already replied but that is not what we usually need.

We have two different algorithms, one constexpr , other not. We can achieve correct choice by selecting "manually" and then shortening it down with preprocessor macros.

Usually such overloads reach same result just by different algorithms. Here for testing purposes I took two algorithms that give never same answers:

#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;
}

Here is a trick of detecting constexpr . I'm pretty sure that it 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))

So what is left is to write a "foo" that selects the algorithm based on argument type 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 here it works like expected.

链接地址: http://www.djcxy.com/p/66592.html

上一篇: GCC c ++ 11使用STL位集<UINT的大量RAM

下一篇: C ++