Reputation: 2888
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.
Upvotes: 6
Views: 1580
Reputation: 39141
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 constexpr
ness 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 aconstexpr
function orconstexpr
constructor, that specialization is not aconstexpr
function orconstexpr
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 aconstexpr
function orconstexpr
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.
Upvotes: 5