如果constexpr尽可能使用最短的代码,我该如何向后移植?

时间:2017-08-09 09:33:29

标签: c++ templates template-meta-programming

我使用此代码来实现类似C#中的类型查询:     

template<class T>
constexpr bool IsSixtyFourBit() {
    return is_same<T, int64_t>() || is_same<T, uint64_t>();
}

template<class T>
constexpr bool IsDouble() {
    return is_same<T, double>() || is_same<T, double_t>();
}

template<class T>
constexpr bool IsFloat() {
    return is_same<T, float>() || is_same<T, float_t>();
}


template<class T>
constexpr bool IsReal() {
    return IsDouble<T>() || IsFloat<T>();
}

template <class T>
constexpr T MakePseudoNumberGenerator(T min, T max) {
    if constexpr (IsSixtyFourBit<T>()) {
        mt19937_64 rng(random_device{}());            // random-number engine used (Mersenne-Twister in this case)
        uniform_int_distribution<T> uni(min, max); // guaranteed unbiased

        return uni(rng);
    } else if constexpr (IsReal<T>()) {
        mt19937_64 rng(random_device{}());            // random-number engine used (Mersenne-Twister in this case)
        uniform_real_distribution<T> uni(min, max); // guaranteed unbiased

        return uni(rng);
    } else {
        mt19937 rng(random_device{}());            // random-number engine used (Mersenne-Twister in this case)
        uniform_int_distribution<T> uni(min, max); // guaranteed unbiased

        return uni(rng);
    }
}

但我无法弄清楚如何使用最少的代码在C ++ 17下为C ++环境重写它...部分专业化应该在这里工作,但它不是那么实用......

完整代码:https://godbolt.org/g/QBs92V

1 个答案:

答案 0 :(得分:2)

根据我的理解,模拟需要最少额外机制和语法变化的if constexpr的方法是使用std::tuple。一般方法是翻译代码

if constexpr (P) {
    T;
} else {
    F;
}

调用封装真假分支的两个多态lambda中的一个:

std::get<P ? 0 : 1>(std::forward_as_tuple(
    [&](auto) { T; },
    [&](auto) { F; }))(0);

这允许将谓词和两个分支保持在相同的顺序和相同的封闭范围内;事实上,可以将仿真代码放在宏检查__cplusplus版本中,同时保持业务逻辑不变。

由于lambdas是多态的,因此将检查它们的语法正确性,并且仅在评估P时进行实例化。

例如,在您的情况下:

template <class T>
constexpr T MakePseudoNumberGenerator(T min, T max) {
    return std::get<IsSixtyFourBit<T>() ? 0 : 1>(std::forward_as_tuple(
    [&](auto) {
        mt19937_64 rng(random_device{}());            // random-number engine used (Mersenne-Twister in this case)
        uniform_int_distribution<T> uni(min, max); // guaranteed unbiased

        return uni(rng);
    }, std::get<IsReal<T>() ? 0 : 1>(std::forward_as_tuple(
    [&](auto) {
        mt19937_64 rng(random_device{}());            // random-number engine used (Mersenne-Twister in this case)
        uniform_real_distribution<T> uni(min, max); // guaranteed unbiased

        return uni(rng);
    },
    [&](auto) {
        mt19937 rng(random_device{}());            // random-number engine used (Mersenne-Twister in this case)
        uniform_int_distribution<T> uni(min, max); // guaranteed unbiased

        return uni(rng);
    }))))(0);
}