Search code examples
c++boostclangstatic-membersstatic-assert

Compile time operations on floating point types


I have some static const floating point member variables, on which I want to do some compile time static asserts. The following code compiles in gcc but fails in both clang and Visual Studio:

#include <boost/static_assert.hpp>
#include <iostream>

template<typename Scalar>
class ProbModel {
public:
  static const Scalar probA;
  static const Scalar probB;

private:
  BOOST_STATIC_ASSERT_MSG(probA < 1, "Weird Parameter");
  BOOST_STATIC_ASSERT_MSG(probB < 1, "Weird Parameter");
  BOOST_STATIC_ASSERT_MSG(probA < probB, "Weird Parameter");
};

// Initializations
template<typename Scalar> const Scalar
ProbModel<Scalar>::probA = 0.3;

template<typename Scalar> const Scalar
ProbModel<Scalar>::probB = 0.6;

int main(int argc, char* argv[]) {
  typedef ProbModel<float> Modelf;
  std::cout << "ProbA = " << Modelf::probA << std::endl;
}

I get errors in Visual Studio 2013 and Clang for the static assert statements complaing about constant expression:

2>..\static_assert_experiments.cpp(11): error C2057: expected constant expression
2>..\static_assert_experiments.cpp(12): error C2057: expected constant expression
2>..\static_assert_experiments.cpp(13): error C2057: expected constant expression

A non c++11 solution for doing this will be highly appreciated. Also is there other ways to do these kind of checks on static parameters?


Solution

  • As dyp stated in comment, floating-point type variables cannot be used in constant expression. A possible workaround would be to use rational number.

    std::ratio is C++11 but can easily be ported to C++03

    template<typename Scalar>
    class ProbModel {
    public:
    
        static Scalar getProbA() { return Scalar(probA::num) / probA::den; }
        static Scalar getProbB() { return Scalar(probB::num) / probB::den; }
    
    private:
        typedef std::ratio<3, 10> probA; // 0.3
        typedef std::ratio<6, 10> probB; // 0.6
    
        BOOST_STATIC_ASSERT_MSG(probA::num < probA::den, "Weird Parameter");
        BOOST_STATIC_ASSERT_MSG(probB::num < probB::den, "Weird Parameter");
        BOOST_STATIC_ASSERT_MSG(probA::num * probB::den < probB::num * probA::den, "Weird Parameter");
    };