【问题标题】:Template arguments of the first template type第一个模板类型的模板参数
【发布时间】:2018-05-09 18:14:04
【问题描述】:

我正在使用一个 API,它接受一个带有单个参数的函数作为回调。回调接受特定类型的单个参数,为了简单起见,我会说它返回一个bool。我试图组合的主要内容是范围检查功能。我的直觉是这样写:

template<class T, T min, T max>
constexpr bool in_range(T val) {
    return (val >= min && val <= max);
}

static_assert(in_range<float, 0.0f, 1.0f>(0.5f), "doesn't work")

但是,这不起作用,所以我默认以这种方式创建函数。

template<class T>
std::function<bool(T)> in_range(T min, T max) {
    auto test = [min, max](T val) {
        return (val >= min && val <= max);
    };
    return test;
}


assert(in_range<float>(0.0f, 1.0f)(0.5f))

有没有办法以第一个函数的形式更多地编写函数,所以我不依赖std::function和运行时生成的lambdas?

【问题讨论】:

  • 为什么不做minmax函数参数呢?
  • 我应该澄清一下我是在 c++11 环境中运行的,所以不能选择自动返回值。
  • 我还没有把它们变成函数参数,因为 API 只接受一个带有单个参数的回调。我可以在设置回调时只编写 lambda,但由于它可以多次重复使用,因此我希望这种模式简洁明了。
  • 这里的问题是浮点类型被排除在函数模板之外吗?您能否为 2 个值参数为双精度值的浮点数编写替代规范?
  • 您确定您正在运行 C++11 环境吗?在您的示例中,您编写了一个 static_assert() 没有错误消息,如果我没记错的话,它是 C++17 功能。

标签: c++ c++11 templates callback constexpr


【解决方案1】:

作为浮点数aren't allowed as template non-type parameters,,您必须将它们作为实际的函数参数而不是模板参数。

如果你想要一个只接受一个参数的函数,你可以通过直接返回 lambda 来避免 std::function 的开销。如果我们使用 C++14,你可以让它返回 auto:

template<class T>
auto in_range(T min, T max) { // Note: could be `constexpr` in C++17
    return [min, max](T val) {
        return (val >= min && val <= max);
    };
}

但是,由于您使用的是 C++11,因此您必须手动写出可调用类型:

template <typename T>
class InRange {
public:
    constexpr InRange(T min, T max)
        : min(std::move(min))
        , max(std::move(max))
    {}

    constexpr bool operator()(T const& val) const {
        return (val >= min && val <= max);
    }

private:
    T min;
    T max;
};

template<class T>
constexpr InRange<T> in_range(T min, T max) {
    return InRange<T>(std::move(min), std::move(max));
}

【讨论】:

    【解决方案2】:

    有没有办法以第一个函数的形式更多地编写函数,所以我不依赖于运行时生成的 std::function 和 lambdas?

    如果您可以将静态全局变量作为模板参数而不是 float 字面量传递,则可以通过引用传递它们

    如下

    #include <iostream>
    
    template <typename T, T const & min, T const & max>
    constexpr bool in_range (T val)
     { return (val >= min && val <= max); }
    
    static constexpr float  f0 { 0.0f };
    static constexpr float  f1 { 1.0f };
    
    int main ()
     {    
       static_assert(in_range<float, f0, f1>(0.5f), "!");
     }
    

    【讨论】:

    • @Barry - 参考模板float 被接受为模板参数,而简单的float 参数不被接受。所以这回答了引用的问题。
    • 是什么让静态全局变量被允许,而文字却不是?这不是我所熟悉的。
    • 啊,没有意识到这是一个浮动的东西。 stackoverflow.com/questions/2183087/…
    • @dfreese:它们更像是引用。引用实际上是变相的指针,它满足模板参数的积分约束。
    • @dfreese - 确切地说:您的原始示例不起作用,因为浮点值不允许模板参数(14.1.7:“不应将非类型模板参数声明为具有浮动点、类或空类型")。但是,在同一点标准中,有一个示例表明指向 double 的指针或引用可以作为非类型模板参数。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-01-29
    • 2021-03-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-02
    相关资源
    最近更新 更多