Consider the following code:
template<typename T>
constexpr inline T fma(T a, T b, T c)
{
return a * b + c;
}
This compiles just fine. But why does it? In theory, constexpr functions can only call other constexpr functions. However, there is no guarantee that the operators will be constexpr functions. For example, let's say I have some type with the following interface:
class someType
{
someType operator + (const someType &rhs);
someType operator * (const someType &rhs);
};
The operators + and * are not constexpr. If I write the following code:
fma(someType(), someType(), someType());
It should fail to compile because a constexpr function is calling non-constexpr functions. But it compiles just fine. Why is this?
I'm using MinGW's G++ compiler with the -std=c++0x option.
If you call a constexpr function using non-constant expressions as its arguments, the function is executed on runtime.
If you do this:
constexpr someType dummy = fma(someType(), someType(), someType());
it will fail, since you are forcing the result to be stored in a constexpr type. That can't be done in compile-time, therefore you get a compile error.
Note that this would work if you provided both a constexpr constructor and a constexpr operator+/* in someType.
From section 7.1.5.6 of the C++11 standard:
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.
This means that a constexpr function template degrades to a non-constexpr function if it is instantiated with template parameters which make it not be a valid constexpr function.
If it wouldn't be a valid constexpr function no matter what template parameters you gave it, then the compiler may complain, but it doesn't have to.
Since templates are mostly checked for errors on use, only when you use it with a type with non constexpr operators it will error.
Related
I'm working on C++17 project which among others have these definitions (in my namespace, of course):
using CppFunction = std::function<int(StatePtr&)>;
template<typename T>
using CppMethod = std::function<int(T*, StatePtr&)>;
Now I declare some functions:
template<typename... Targs, typename F>
constexpr CppFunction CppFunctionNative(F func);
template<typename... Targs, typename F, typename T = (deducing class from F here) >
constexpr CppMethod<T> CppMethodNative(F func);
To my surprise, first declaration cause compiler error Constexpr function's return type is not a literal type, but second works just fine.
Why does this happen? Is it related to the fact that second function's return type is template?
UPD: simplified standalone example:
#include <functional>
using CppFunction = std::function<int(int&)>;
template<typename T>
using CppMethod = std::function<int(T*, int&)>;
// Clang will complain
template<typename F>
constexpr CppFunction CppFunctionNative(F func) {};
// Clang will not complain
template<typename F, typename T = /*(deducing class from F here)*/char >
constexpr CppMethod<T> CppMethodNative(F func) {};
// main() function doesn't matter
int main() {
CppFunctionNative(0);
CppMethodNative(0);
return 0;
};
Interestingly enough, OnlineGDB and offline GCC 8.3.0 doesn't complain about this, but my Clang 8 does.
To my surprise, first declaration cause compiler error Constexpr function's return type is not a literal type, but second works just fine.
Why does this happen? Is it related to the fact that second function's return type is template?
Yes. In the first case, the compiler can prove that that specific specialization of std::function is not a literal type.
In the second case, it must know T before it knows if the specific specialization of std::function is a literal type.
template<class T>
struct example {
virtual T get() const {return {};}
~example() {}
};
template<>
struct example<int> {};
#if 0
template<class F>
constexpr example<double> test( F ) { return {}; }
#endif
template<class T, class F>
constexpr example<T> test2( F ) { return {}; }
Live example
test is illegal; test2 is fine. In fact, test2<int>( 3.14 ) is a legal constexpr call.
Now, std::function has no such specialization, but that is not something the compiler is required to prove; doing so in general requires solving the halting problem, which is something C++ standard tries to avoid asking compilers to do.
As mentioned by #MaxLanghof, this kind of error results in an "ill-formed, no diagnostic required" program. The compiler is not forced to detect that your constexpr function cannot be constexpr, but if you do that the compiler is free to do anything, including generate an error message (or worse things).
So GCC is not wrong to omit the error, and clang is not wrong to emit an error. Clang's error emission is, in a sense, a higher QoI than gcc's omission.
Edit: Yakk's answer is more complete - one has to of course consider the theoretical possibility of std::function specializations!
constexpr means "there is at least one set of arguments for which this function produces a constant expression". If no such arguments exist, the program is ill-formed, no diagnostic required. This means it is up to the compiler whether it completely ignores this issue, whether it only complains at instantiation-time or whether it already barks at the declaration.
clang is evidently smart/eager enough to realize that a function template with a non-literal return type can never be constexpr. gcc does not seem to bother checking this - it's not required to. Your program is still wrong though - std::function is not a literal type and can thus never be returned from a constexpr function.
I tried to implement a value template similar to std::is_constructible with the exception to only be true when the type is copiable in a constexpr environment (i.e. its copy constructor is constexpr qualified). I arrived at the following code:
#include <type_traits>
struct Foo {
constexpr Foo() = default;
constexpr Foo(const Foo&) = default;
};
struct Bar {
constexpr Bar() = default;
Bar(const Bar&);
};
namespace detail {
template <int> using Sink = std::true_type;
template<typename T> constexpr auto constexpr_copiable(int) -> Sink<(T(T()),0)>;
template<typename T> constexpr auto constexpr_copiable(...) -> std::false_type;
}
template<typename T> struct is_constexpr_copiable : decltype(detail::constexpr_copiable<T>(0)){ };
static_assert( is_constexpr_copiable<Foo>::value, "");
static_assert(!is_constexpr_copiable<Bar>::value, "");
Now I ask myself if this is according to standard, since compilers seem to disagree about the output.
https://godbolt.org/g/Aaqoah
Edit (c++17 features):
While implementing the somewhat different is_constexpr_constructible_from, with c++17's new auto non-type template type, I once again found a difference between compilers, when dereferencing a nullptr in a constexpr expression with SFINAE.
#include <type_traits>
struct Foo {
constexpr Foo() = default;
constexpr Foo(const Foo&) = default;
constexpr Foo(const Foo*f):Foo(*f) {};
};
struct Bar {
constexpr Bar() = default;
Bar(const Bar&);
};
namespace detail {
template <int> struct Sink { using type = std::true_type; };
template<typename T, auto... t> constexpr auto constexpr_constructible_from(int) -> typename Sink<(T(t...),0)>::type;
template<typename T, auto... t> constexpr auto constexpr_constructible_from(...) -> std::false_type;
}
template<typename T, auto... t> struct is_constexpr_constructible_from : decltype(detail::constexpr_constructible_from<T, t...>(0)){ };
constexpr Foo foo;
constexpr Bar bar;
static_assert( is_constexpr_constructible_from<Foo, &foo>::value, "");
static_assert(!is_constexpr_constructible_from<Foo, nullptr>::value, "");
static_assert(!is_constexpr_constructible_from<Bar, &bar>::value, "");
int main() {}
https://godbolt.org/g/830SCU
Edit: (April 2018)
Now that both compiler supposedly have support for C++17, I have found the following code to work even better (does not require a default constructor on `T`), but only on clang. Everything is still the same but replace the namespace `detail` with the following:
namespace detail {
template struct Sink {};
template constexpr auto sink(S) -> std::true_type;
template constexpr auto try_copy() -> Sink;
template constexpr auto constexpr_copiable(int) -> decltype(sink(std::declval,0)>>()));
template constexpr auto constexpr_copiable(...) -> std::false_type;
}
https://godbolt.org/g/3fB8jt
This goes very deep into parts of the standard about unevaluated context, and both compilers refuse to allow replacing `const T*` with `const T&` and using `std::declval()` instead of the `nullptr`-cast. Should I get confirmation that clang's behaviour is the accepted standardized behaviour, I will lift this version to an answer as it requires only exactly what has been asked.
Clang accepts some undefined behaviour, dereferencing nullptr, in the evaluation of an unevaluated operand of decltype.
The toughest of the challenges, giving a single function evaluating whether a constexpr constructor from const T& exists for arbitrary T, given here seems hardly possible in C++17. Luckily, we can get a long way without. The reasoning for this goes as follows:
Knowing the problem space
The following restrictions are important for determining if some expression can be evaluated in constexpr content:
To evaluate the copy constructor of T, a value of type const T& is needed. Such a value must refer to an object with active lifetime, i.e. in constexpr context it must refer to some value created in a logically enclosing expression.
In order to create this reference as a result of temporary promotion for arbitrary T as we would need to know and call a constructor, whose arguments could involve virtually arbitrary other expressions whose constexpr-ness we would need to evaluate. This looks like it requires solving the general problem of determining the constexprness of general expressions, as far as I can understand. ¹
¹ Actually, If any constructor with arguments, including the copy constructor, is defined as constexpr, there must be some valid way of constructing a T, either as aggregate initialization or through a constructor. Otherwise, the program would be ill-formed, as can be determined by the requirements of the constexpr specifier §10.1.5.5:
For a constexpr function or constexpr constructor that is neither defaulted nor a template, if no argument values exist such that an invocation of the function or constructor could be an evaluated subexpression of a core constant expression, or, for a constructor, a constant initializer for some object ([basic.start.static]), the program is ill-formed, no diagnostic required.
This might give us a tiny loophole.²
So the expression best be an unevaluated operand §8.2.3.1
In some contexts, unevaluated operands appear ([expr.prim.req], [expr.typeid], [expr.sizeof], [expr.unary.noexcept], [dcl.type.simple], [temp]).
An unevaluated operand is not evaluated
Unevaluated operands are general expressions but they can not be required to be evaluatable at compile time as they are not evaluated at all. Note that the parameters of a template are not part of the unevaluated expressiont itself but rather part of the unqualified id naming the template type. That was part of my original confusion and tries in finding a possible implementation.
Non-type template arguments are required to be constant expressions §8.6 but this property is defined through evaluation (which we have already determined to not be generally possible). §8.6.2
An expression e is a core constant expression unless the evaluation of e, following the rules of the abstract machine, would [highlight by myself] evaluate one of the following expressions:
Using noexpect for the unevaluated context has the same problem: The best discriminator, inferred noexceptness, works only on function calls which can be evaluated as a core-constant expression, so the trick mentionend in this stackoverflow answer does not work.
sizeof has the same problems as decltype. Things may change with concepts.
The newly introduced if constexpr is, sadly, not an expression but a statement with an expression argument. It can therefore not help enforce the constexpr evaluatability of an expression. When the statement is evaluated, so is its expression and we are back at the problem of creating an evaluatable const T&. Discarded statements have not influence on the process at all.
Easy possibilities first
Since the hard part is creating const T&, we simply do it for a small number of common but easily determined possibilities and leave the rest to specialization by extremely special case callers.
namespace detail {
template <int> using Sink = std::true_type;
template<typename T,bool SFINAE=true> struct ConstexprDefault;
template<typename T>
struct ConstexprDefault<T, Sink<(T{}, 0)>::value> { inline static constexpr T instance = {}; };
template<typename T> constexpr auto constexpr_copiable(int) -> Sink<(T{ConstexprDefault<T>::instance}, 0)>;
template<typename T> constexpr auto constexpr_copiable(...) -> std::false_type;
}
template<typename T>
using is_constexpr_copyable_t = decltype(detail::constexpr_copiable<T>(0));
Specializing details::ConstexprDefault must be possible for any class type declaring a constexpr copy constructor, as seen above. Note that the argument does not hold for other compound types which don't have constructors §6.7.2. Arrays, unions, references and enumerations need special considerations.
A 'test suite' with a multitude of types can be found on godbolt. A big thank you goes to reddit user /u/dodheim from whom I have copied it. Additional specializations for the missing compound types are left as an exercise to the reader.
² or What does this leave us with?
Evaluation failure in template arguments is not fatal. SFINAE makes it possible to cover a wide range of possible constructors. The rest of this section is purely theoretical, not nice to compilers and might otherwise be plainly stupid.
It is potentially possible to enumerate many constructors of a type using methods similar to magic_get. Essentially, use a type Ubiq pretending to be convertible to all other types to fake your way through decltype(T{ ubiq<I>()... }) where I is a parameter pack with the currently inspected initializer item count and template<size_t i> Ubiq ubiq() just builds the correct amount of instances. Of course in this case the cast to T would need to be explicitely disallowed.
Why only many? As before, some constexpr constructor will exist but it might have access restrictions. This would give a false positive in our templating machine and lead to infinite search, and at some time the compiler would die :/. Or the constructor might be hidden by an overload which can not be resolved as Ubiq is too general. Same effect, sad compiler and a furious PETC (People for the ethical treatment of compilers™, not a real organization). Actually, access restrictions might be solvable by the fact that those do not apply in template arguments which may allow us to extract a pointer-to-member and [...].
I'll stop here. As far as I can tell, it's tedious and mostly unecessary. Surely, covering possible constructor invocations up 5 arguments will be enough for most use cases. Arbitrary T is very, very hard and we may as well wait for C++20 as template metaprogramming is once again about to change massively.
In the following piece of C++11 code, the function get is constexpr
but it tries to construct an instance via the non-constexpr constructor.
template <typename T>
struct S
{
S() {}
static constexpr S get() { return S(); }
};
int main()
{
// S<int> s1;
// auto s2 = s1.get();
}
While this code compiles with GCC, it fails with the compiler we use at
work with the message
constexpr function return is non-constant.
We started a discussion whether the compiler is allowed to issue an error in
this case. I think that the compiler has to accept the code. Otherwise I do
not see how std::time_point could work in C++11 because its constructor is
constexpr only since C++14.
So is this a quality-of-implementation thing or does the standard say
something about uninstantiated templates w.r.t constexpr?
Further, would it change anything if the code in the comments were
activated (i.e. invoking a constexpr function on a non-constexpr
object)?
This line is fine:
S<int> s1;
but the following definition of get is ill-formed:
static constexpr S get() { return S(); }
since it does not return a literal type since S does not have a constexpr constructor.
From the draft C++11 standard section 7.1.5 The constexpr specifier [dcl.constexpr]:
The definition of a constexpr function shall satisfy the following constraints:
its return type shall be a literal type;
and later on the section it says (emphasis mine):
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.
Note in the non-template case both gcc and clang generate an error since the return type is not a literal see it live.
#include <utility>
struct A {
constexpr auto one(int a) {
return std::integral_constant<int, _data[a]>{};
}
constexpr int two(int a) const {
return _data[a];
}
int _data[10];
};
int main() {
constexpr auto ex = A{{1,2,3,4,5,6,7,8,9,10}};
std::integral_constant<int, ex.two(3)> b{};
}
The code above will not compile in trunk Clang. The error is in the one() member function, and says:
cc.cpp:57:44: note: implicit use of 'this' pointer is only allowed
within the evaluation of a call to a 'constexpr' member function.
Obviously, the function is marked constexpr, and if you comment out the one() member, everything compiles fine, so we are clearly able to create the integral_constant from the ex, but not directly from the struct? It seems like, when I need the auto return type deduction, it fails and claims the function is not constexpr?
Is this expected? I feel like it should not be a problem, and I would be surprised if this was expected behavior.
If you consider this statement in [dcl.constexpr]/7:
A call to a constexpr function produces the same result as a call to an equivalent non-constexpr function in all respects except that a call to a constexpr function can appear in a constant expression.
Consider the non-constexpr equivalent function A::one(). _data[a] cannot be used in a constant expression (as a non-type template argument) because it would involve the evaluation of this, from [expr.const]:
A conditional-expression e is a core constant expression unless the evaluation of e, following the rules of the
abstract machine (1.9), would evaluate one of the following expressions:
(2.1) — this (5.1.1), except in a constexpr function or a constexpr constructor that is being evaluated as
part of e;
Since the non-constexpr equivalent is ill-formed, it is reasonable that the constexpr function give the same result.
Ont the other hand, two() is a well-formed member function regardless of constexpr and your use of ex.two(3) is valid as a constant expression - that's why it compiles.
constexpr functions are made so that they can be called both at compile-time and run-time.
Code with a constexpr function is well-formed if you can omit constexpr and get a proper plain function. In other words it must compile as a run-time function.
If the body of constexpr function cannot be calculated at compile-time, it's still compiled, but you cannot use it in a compile-time context such as template arguments.
If constexpr method is called on constexpr object, this is considered constexpr.
In case of one it is ill-formed, because when it's compiled to be run at run-time, _data[a] is considered to be a run-time expression, because a is not a constant expression, even though this and this->_data are.
In case of two it compiles fine, because it works fine at runtime, and at compile-time this is constexpr as much as a, so that this->_data[a] is constexpr and everything works fine.
I found a weird difference between explicit and automatic trailing return types.
In the following code, we define a struct templated on an integer and an iter function, which take one object of this type as argument. The return type depends on the result of calling itself after decrementing the template value.
To break the instantiation loop (or so I thought), I provide a specialization which returns a non-dependent type.
We have a toy main to instantiate the templates.
Here is a bit of code:
template<int i> struct Int {};
constexpr auto iter(Int<0>) -> Int<0>;
template<int i> constexpr auto iter(Int<i>) -> decltype(iter(Int<i-1>{}));
int main(){
decltype(iter(Int<10>{})) a;
}
This code does not work in both gcc 4.9 and clang 3.5. Both trigger infinite instantiation (they don't match the specialized base case).
rec.cpp:11:62: fatal error: recursive template instantiation exceeded maximum depth of 256
template<int i> constexpr auto iter(Int<i>) -> decltype(iter(Int<i-1>{}));
Now, if we use C++14 decltype(auto) and we provide a body for the template which returns the exact same thing:
template<int i> struct Int {};
constexpr auto iter(Int<0>) -> Int<0>;
template<int i>
constexpr auto iter(Int<i>) -> decltype(auto) {
return iter(Int<i-1>{});
}
int main(){
decltype(iter(Int<10>{})) a;
}
This now works for both compilers and behave as expected.
I tried different ways to express the specialization and moved it around a bit (to be careful about its location), but that didn't prevent its self-immolation ;(
I also tried to sprinkle the code with more decltype and declval, but I can't seem to get the C++11 syntax working.
Could someone explain the difference between the two syntaxes for the name lookup?
It's because of the relative ordering of overload resolution, template overload resolution, template declaration instantiation, and template definition instantiation.
Let's look at the C++11 case first. When the compiler needs to evaluate decltype(iter(Int<0>{})), it performs overload resolution on the name iter called with arguments prvalue Int<0>. Since a template is in the overload set, we apply 14.8.3 [temp.over]:
1 - A function template can be overloaded either by (non-template) functions of its name or by (other) function templates of the same name. When a call to that name is written (explicitly, or implicitly using the operator notation), template argument deduction (14.8.2) and checking of any explicit template arguments (14.3) are performed for each function template to find the template argument values (if any) that can be used with
that function template to instantiate a function template specialization that can be invoked with the call arguments. [...]
As a result, the declaration template<int i> constexpr auto iter(...) -> ... is instantiated (14.7.1p10 [temp.inst]) with i = 0, which forces the evaluation of decltype(iter(Int<-1>{})) and off down the rabbit hole of negative integers we go.
It doesn't matter that constexpr auto iter(Int<0>) -> Int<0> would be a better overload (by 13.3.3p1 [over.match.best]), because we never get that far; the compiler is away marching merrily towards negative infinity.
By contrast, with C++14 deduced return types 7.1.6.4p12 [dcl.spec.auto] applies:
12 - Return type deduction for a function template with a placeholder in its declared type occurs when the definition is instantiated [...]
Since definition instantiation occurs after template overload resolution (14.7.1p3), the bad template iter<0> is never instantiated; 14.8.3p5:
5 - Only the signature of a function template specialization is needed to enter the specialization in a set of candidate functions. Therefore only the function template declaration is needed to resolve a call for which a template specialization is a candidate.
The "signature" of iter<0> here is (Int<0>) -> decltype(auto), a signature containing a placeholder type (7.1.6.4).
Suggested workaround: use SFINAE to prevent any attempted call to iter(Int<-1>{}):
template<int i> constexpr auto iter(Int<i>)
-> decltype(iter(typename std::enable_if<i != 0, Int<i-1>>::type{}));
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^
Note that the SFINAE has to go inside the decltype, and indeed inside the call to iter.