Made to Order Software Corporation Logo

Metaprogramming in C++ to create functions that depend on their input parameters

I've been using metaprogramming for a while now. An interesting aspect to the ability to define an invalid (unavailable) type, allows you to declare functions that do not get selected by the C++ template system.

The following is a simple example where you want to test a version where the major, minor and patch version numbers are defined as an undefined type T which could be a signed or an unsigned type while compiling. If unsigned, the return value < 0; statement will generate a warning and for safer programming, you should not allow any warnings (we use the -Werror command line option of g++ to turn all warnings in errors and that forces us to fix them all, and frankly 99.9% of the time the compile is correct).

To avoid the warning and still return the correct result, in this case we can't just cast the version number to the corresponding signed version (see the std::make_signed<> template).

template<typename T>
constexpr typename std::enable_if<std::is_signed<T>::value, bool>::type is_negative(T const value)
{
    return value < 0;
}


template<typename T>
constexpr typename std::enable_if<!std::is_signed<T>::value, bool>::type is_negative(T const)
{
    // unsigned type T can never be negative
    return false;
}


template<typename T>
constexpr void validate_version(T const major, T const minor, T const patch)
{
    if(major == 0 && minor == 0)
    {
        throw cppthread_logic_error("the plugin version cannot be 0.0.");
    }

    if(is_negative(major)
    || is_negative(minor)
    || is_negative(patch))
    {
        throw cppthread_logic_error("the plugin version cannot use negative numbers.");
    }
}

In this case, the is_negative() function always returns false if the type T is an unsigned integer such as std::uint32_t.

The original source code can be found in our cppthread project on github.