10

In C++11 we get constexpr:

constexpr int foo (int x) { return x + 1; } 

Is it possible to make invocations of foo with a dynamic value of x a compile time error? That is, I want to create a foo such that one can only pass in constexpr arguments.

5
  • 1
    You can always turn it into a function template: template<int x> int foo() { return x + 1; } Commented Jul 15, 2013 at 20:54
  • 1
    Note that constexpr was partially called into being to counteract all the syntactical workarounds you are going to see in the answers here. Commented Jul 15, 2013 at 20:57
  • #define foo(N) foo<N>() looks viable to me. Commented Jul 15, 2013 at 20:58
  • Alternatively, in non-evaluated contexts, #define REQUIRE_CEXPR(E) []{ constexpr auto x = E; return x; }() and you can say foo(REQUIRE_CEXPR(1 + 2)) (C++14). For C++11, you can do []()->typename std::decay<decltype((E))>::type to explicitly specify the type. Uglier though :) Commented Jul 15, 2013 at 21:04
  • Non-answer: store the result in a constexpr. Commented Jul 15, 2013 at 22:07

4 Answers 4

9

Replace it with a metafunction:

template <int x> struct foo { static constexpr int value = x + 1; }; 

Usage:

foo<12>::value 
Sign up to request clarification or add additional context in comments.

2 Comments

Or better, give it an operator() so that is resembles a function call.
@rubenvb: Even better, use a variable template: template <int N> int bar = foo<N>::value;. Usage: bar<12>. Available in C++14.
4

Unfortunately, there is no way guarantee that a constexpr function, even the most trivial one, will be evaluated by the compiler unless absolutely necessary. That is, unless it appears in a place where its value is required at compile time, e.g. in a template. In order to enforce the compiler to do the evaluation during compilation, you can do the following:

constexpr int foo_implementation (int x) { return x + 1; } #define foo(x) std::integral_constant<int, foo_implementation(x)>::value 

and then use foo in your code as usual

int f = foo(123); 

The nice thing about this approach is that it guarantees compile-time evaluation, and you'll get a compilation error if you pass a run-time variable to foo:

int a = 2; int f = foo(a); /* Error: invalid template argument for 'std::integral_constant', expected compile-time constant expression */ 

The not so nice thing is that it requires a macro, but this seems currently inevitable if you want both guaranteed compile-time evaluation and pretty code. (I'd love to be proven wrong though!)

Comments

2

Yes, it can now be done in purely idiomatic C++, since C++20 added support for this kind of problem. You annotate a function with consteval and can be sure that it's being evaluated during compile time. https://en.cppreference.com/w/cpp/language/consteval

consteval int foo( int x ) { return x + 1; } int main( int argc, char *argv[] ) { return foo( argc ); // This will not compile return foo( 1 ); // This works } 

Also see this godbolt.org demo in the 3 most relevant compilers.

Comments

1

I would use static_assert as shown in this example

#include<iostream> constexpr int foo(int x) { return x+1; } int main() { // Works since its static std::cout << foo(2) << std::endl; static_assert(foo(2) || foo(2) == 0, "Not Static"); // Throws an compile error int in = 3; std::cout << foo(in) << std::endl; static_assert(foo(in) || foo(in) == 0, "Not Static"); } 

For more infos: http://en.cppreference.com/w/cpp/language/static_assert

2 Comments

I don't have a compiler ATM with constexpr, but wouldn't this idea extend to putting the static_assert directly into foo? E.g. constexpr int foo(int x) { static_assert(x == x, "Not Static"); return x+1; }
@ThomasEding. You could but then you would loose the flexibility of using the same function as run-time-evaluated function. Since static_assert checked at compile time it will also not affect runtime.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.