7

Can I force compiler to accept only a constexpr or a non-variable input to a function?

I am looking for allowing only compile time values to a function. Either using template or any other method.

Here, there is a working example for int templates. The problem with doubles is that they cannot be used as template arguments.

#include <iostream>

template <double x>
void show_x()
{
    std::cout<<"x is always "<<x<<" in the entire program."<<std::endl;
}

int main()
{
    show_x<10.0>();
    return 0;
}

error: ‘double’ is not a valid type for a template non-type parameter


Update

To those who have marked this question as a duplicate, I have to say:

I ask question

How to solve problem A?

and

Solution B does not work for problem A, I need another solution

Then you linked me to why solution B does not work.

That is totally illogical.

Community
  • 1
  • 1
ar2015
  • 5,558
  • 8
  • 53
  • 110
  • 2
    @m.s., I do not ask why I cannot make template from `double`. I am asking how can I only allow compile time values to a function. Either using template or any other method. – ar2015 Sep 11 '16 at 07:25
  • To clarify, why can't you pass this as a normal function parameter? – Oliver Charlesworth Sep 11 '16 at 07:33
  • @OliverCharlesworth, for security reasons. I am planning to use this function for time synchronization and the step time should not be variable otherwise an unpredictable behavior will happen. There is always a way to get around this problem. However, I prefer to solve it this way. – ar2015 Sep 11 '16 at 07:34
  • Then why not a global `static const double x = 10.0;`? – Oliver Charlesworth Sep 11 '16 at 07:39
  • 1
    "for security reasons" ?? Though I also think this question should be reopened. – xaxxon Sep 11 '16 at 07:40
  • @OliverCharlesworth, because this number has to be decided from `main` function. – ar2015 Sep 11 '16 at 07:43
  • Maybe you could use an int instead and divide it by `1000` or some other number? – HolyBlackCat Sep 11 '16 at 07:47
  • @HolyBlackCat, There are other methods to get around. However, still solving the above question is important to me. – ar2015 Sep 11 '16 at 07:49
  • Assigning to `constexpr` variable? Same constant expression requirement as for template arguments, wider range of allowed types. – Revolver_Ocelot Sep 11 '16 at 07:52
  • @Revolver_Ocelot, I didnt get your point. Could you please explain more? – ar2015 Sep 11 '16 at 07:53
  • 1
    Another approach: use rational arithmetics and `std::ratio`. This is what standard library does when it needs compile-time fractional number. – Revolver_Ocelot Sep 11 '16 at 08:00
  • The title suggests you want to reject `float` for example but allow `double`, but then the first sentence goes off and talks about compile-time stuff. Please clarify. – M.M Sep 11 '16 at 09:55
  • Also it is unclear what you mean by "x is always x" , since the person could call show_x(10.0) and then show_x(20.0). It would be better to post a `main` function with some sample calls to `show_x`, clearly indicating which calls should succeed and which calls should be rejected. – M.M Sep 11 '16 at 09:57
  • @M.M, I assumed this function is called only from one point from the main but inside a `for` loop. – ar2015 Sep 11 '16 at 09:58

2 Answers2

4

Here are 2 ways:

Update:

Concerns about user-circumvention have been addressed. Now, X::value() s acquired by a constexpr variable within the function body before being used. It is now not possible to pass an X without a constexpr method called value().

#include <iostream>


  struct always_10
  {
    constexpr static double value() { return 10.0; }
  };

template <class X>
void show_x()
{
  constexpr auto x = X::value();
  std::cout<<"x is always "<< x <<" in the entire program."<<std::endl;
}

template<class X>
void show_x(X x_)
{
  constexpr auto x = x_.value();
  std::cout<<"x is always "<< x <<" in the entire program."<<std::endl;
}

int main()
{
    show_x<always_10>();
    show_x(always_10());
    return 0;
}
Richard Hodges
  • 68,278
  • 7
  • 90
  • 142
  • 1
    Your method works fine. However, still `constexpr` is not a requirement for `show_x`. One user can get around the library by mistake. – ar2015 Sep 11 '16 at 08:29
  • @ar2015 I'm not sure i understand. – Richard Hodges Sep 11 '16 at 09:11
  • I think ar2015 is saying that this is a bit of a cheat because, rather than the function itself enforcing the constraint, you have to do it yourself by remembering to pass an object of a certain type that enforces the constraint. As such this may be a decent practical solution in many cases (and frankly I personally wouldn't bother going further than this), but I can see why ar2015 may believe that this doesn't really satisfy the spirit of the question. – Lightness Races in Orbit Sep 11 '16 at 10:26
4

I'm not sure exactly what you want, but here is a way to reject non-constant expressions in a function call. Unfortunately it uses a macro which is bad because of name pollution, but maybe if you give your function a strange name then it won't hurt too much:

void f(double d) {}
#define f(x) do { constexpr decltype(x) var = x; f(var); } while (0)

int main() 
{
    f(1.0);      // OK
    f(1 + 2);    // OK, constant expression with implicit conversion
    double e = 5.0;
    f(e);        // compilation error, `e` is not a constant expression
}

If you want to reject constant expressions which aren't exactly double type already, that would be possible too (not sure from your question whether that is a requirement).

M.M
  • 138,810
  • 21
  • 208
  • 365