7

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.

Drew Dormann
  • 59,987
  • 13
  • 123
  • 180
Publius
  • 1,184
  • 2
  • 10
  • 27
  • For an example where it's blatantly obvious it can't optimize everything out, it compiles with GCC 4.7.1 when the three arguments are inputted, and the result printed: http://ideone.com/aBRPU – chris Sep 09 '12 at 03:52
  • try this: `constexpr someType dummy = fma(someType(), someType(), someType());` ;) – mfontanini Sep 09 '12 at 03:55
  • Ooh, I just found in the standard that `constexpr` functions are implicitly inline, if that saves you space. – chris Sep 09 '12 at 03:55
  • mfontanininininini: That doesn't work, but it doesn't really answer my original question. – Publius Sep 09 '12 at 03:57
  • 2
    Yes it does. If you call a constexpr function using non-constant expressions as its arguments, the function is executed on runtime. In my example, since you force the result to be stored in a constexpr type, you get a compile error, since that can't be done in compile-time. PS: why do you laugh at my surname? – mfontanini Sep 09 '12 at 04:00
  • I wasn't making fun of it. I just typed "ni" too many times and so, to indicate that I wasn't trying to get your name right and failing, I just typed an obviously incorrect number of "ni". Also, thanks for the answer: functions declared constexpr aren't forced to be compiled at compile-time. If you want you can submit that as an answer and I'll accept it. – Publius Sep 09 '12 at 04:01
  • Don't worry, I didn't get offended :P. Just messing with you. – mfontanini Sep 09 '12 at 04:07

3 Answers3

5

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.

mfontanini
  • 21,410
  • 4
  • 65
  • 73
5

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.

Vaughn Cato
  • 63,448
  • 5
  • 82
  • 132
0

Since templates are mostly checked for errors on use, only when you use it with a type with non constexpr operators it will error.

Daniel
  • 30,896
  • 18
  • 85
  • 139