Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Non-constexpr function's use in constexpr constructor is valid

The following is valid in gcc 4.8:

class Value {
    private:
        static std::vector<float> compile_time_vector;
        const bool compile_time_bool;

        static bool f(void) {
            compile_time_vector.push_back(2.3);

            return true;
        }

    public:
        template <typename type_t>
        constexpr Value(const type_t& value): compile_time_bool(f()) {}
};

std::vector isn't designed to work at compile time, so exactly what kind of code is this generating? I've used the class to make sure it isn't optimized out.

like image 966
NmdMystery Avatar asked Dec 07 '13 04:12

NmdMystery


1 Answers

This is ill-formed, but no diagnostic is required. The problem is that f() in constexpr Value(const type_t& value): compile_time_bool(f()) may not appear in a constant expression for any template argument. But consider:

struct A{};
struct B{};

bool foo(A);
constexpr bool foo(B) { return {}; }

template<class T>
constexpr bool bar(T p) { return foo(p); }

Here, the constexprness of bar depends on the template argument. Therefore:

constexpr A a{};
constexpr B b{};

//constexpr auto ba {bar(a)};  // error
constexpr auto ba {bar(b)};    // fine
auto ba2 {bar(a)};             // fine

A function template marked as constexpr can produce constexpr and non-constexpr specializations, depending on the template arguments.

It is probably hard or impossible to check if a function template is not constexpr for any set of template arguments (in the OP's case, it could be possible to see that as f() unambiguously refers to Value::f). Therefore, no diagnostic is required.


The relevant paragraph is [dcl.constexpr]/6:

If the instantiated template specialization of a constexpr function template or member function of a class template would fail to satisfy the requirements for a constexpr function or constexpr constructor, that specialization is not a constexpr function or constexpr constructor. [Note: If the function is a member function it will still be const as described below. — end note ] If no specialization of the template would yield a constexpr function or constexpr constructor, the program is ill-formed; no diagnostic required.

N.B. the const thing will be lifted in C++1y, so better mark member functions (not ctors, obviously) both as both constexpr and const.


Effectively, the program has UB. But once you instantiate the ctor in a context that requires a constant expression, your compiler should complain -- as does clang++3.4

Both compilers seem to accept your program if you use the ctor in a context where a constant expression is not required. I'd say that's an extension, but it's as hard to issue a warning in this case ("extension used, nonportable code") as to diagnose the program is ill-formed in the first place.

like image 80
dyp Avatar answered Oct 30 '22 11:10

dyp