10
votes

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.

4
You can always turn it into a function template: template<int x> int foo() { return x + 1; } - Andy Prowl
Note that constexpr was partially called into being to counteract all the syntactical workarounds you are going to see in the answers here. - rubenvb
#define foo(N) foo<N>() looks viable to me. - Johannes Schaub - litb
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 :) - Johannes Schaub - litb
Non-answer: store the result in a constexpr. - Casey

4 Answers

9
votes

Replace it with a metafunction:

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

Usage:

foo<12>::value
3
votes

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!)

1
votes

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

1
votes

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.