I'm getting inconsistent results for std::is_constructible<void()>::value
. My interpretation of the standard is that it should be false. However, Clang, with both libc++ and libstdc++*, gives true. GCC and MSVC both give false. Which result is correct?
Here is the standardese, N4527 [meta.unary.prop]/7:
Given the following function declaration:
template <class T> add_rvalue_reference_t<T> create() noexcept;
the predicate condition for a template specialization
is_constructible<T, Args...>
shall be satisfied if and only if the following variable definition would be well-formed for some invented variablet
:T t(create<Args>()...);
Note: This text changed slightly from C++11 (N3485), where create
was not marked noexcept
. However, the results of my tests did not change when accounting for this.
Here is my minimal test case of both the type trait and the standardese definition:
#include <type_traits>
static_assert(std::is_constructible<void()>::value, "assertion fired");
template<typename T>
std::add_rvalue_reference_t<T> create() noexcept;
template<typename T, typename... Args>
void foo() {
T t(create<Args>()...);
}
int main() {
foo<void()>();
}
Clang (HEAD, libc++):
foo<void()>
did NOT compileClang (HEAD, libstdc++)*:
foo<void()>
did NOT compileGCC (HEAD, libstdc++):
foo<void()>
did NOT compileMSVC (version 19 via http://webcompiler.cloudapp.net/):
foo<void()>
did NOT compile (requires commenting out the static assertion)*__GLIBCXX__
is not defined when Clang is used both with no -stdlib
option and with -stdlib=libstdc++
. I am unsure of whether libstdc++ is actually being used. If my interpretation of the standard is correct, then I am unsure of whether it is a bug with Clang or with libc++.
Keep reading. From the same paragraph:
Access checking is performed as if in a context unrelated to
T
and any of theArgs
. Only the validity of the immediate context of the variable initialization is considered. [ Note: The evaluation of the initialization can result in side effects such as the instantiation of class template specializations and function template specializations, the generation of implicitly-defined functions, and so on. Such side effects are not in the “immediate context” and can result in the program being ill-formed. —end note ]
The assertion only fails when the template constructor is instantiated. However, as cleared up in the note, that assertion is not in the immediate context of the variable definition that is considered, and thus does not affect its "validity". So the compilers can count that definition as valid, even if actually attempting to construct a void()
results in an ill-formed program.
Note that the compilers are also allowed to, instead of having is_constructible yield false, just reject the original program based on the assertion.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With