代码之家  ›  专栏  ›  技术社区  ›  Aleph0

用于比较变量内容的函数未能编译

  •  2
  • Aleph0  · 技术社区  · 6 年前

    在我的项目中我使用 boost-variant 彻底地。因此,对于我的单元测试,我需要根据特定的 T 有一定的内容 t .

    所以我安装了这个功能 cmpVariant 唯一的目的是从我的单元测试中消除混乱。

    在某些情况下,类型 T 未配备 operator== ,以便用户可以传递满足 相等比较要求 ( https://en.cppreference.com/w/cpp/named_req/EqualityComparable )

    现在,由于一些不明确的原因,以下代码无法编译。它说,没有匹配函数?

    Clang 6.0.1编译器错误

    prog.cc:22:5: error: no matching function for call to 'cmpVariant'
        cmpVariant(number, 3.2, lambdaEquiv); // Fails!
        ^~~~~~~~~~
    prog.cc:6:6: note: candidate template ignored: could not match 'function<bool (const type-parameter-0-1 &, const type-parameter-0-1 &)>' against '(lambda at prog.cc:19:24)'
    bool cmpVariant(
         ^
    1 error generated.
    

    有人知道为什么吗?

    代码

    #include <iostream>
    #include <boost/variant.hpp>
    #include <functional>
    
    template<typename V, typename T>
    bool cmpVariant(
        const V& variant,
        const T& t,
        const std::function<bool(const T& u, const T& v)>& equiv = [](const T& u, const T& v) {return u == v; })
    {
        if (variant.type() != typeid(t)) return false;
        auto v = boost::get<T>(variant);
        return equiv(v, t);
    }
    
    int main(int, char**) {
        boost::variant<double, int> number{ 3.2 };
        cmpVariant(number, 3.2);
        auto lambdaEquiv = [](const double& x, const double& y) { return x == y; };
        std::function<bool(const double&, const double&)> equiv = lambdaEquiv;
        cmpVariant(number, 3.2, equiv); // Works!
        cmpVariant(number, 3.2, lambdaEquiv); // Fails!
    }
    
    2 回复  |  直到 6 年前
        1
  •  3
  •   lubgr    6 年前

    编译器无法将lambda与函数参数类型匹配。您可以通过显式实例化函数调用来解决此问题:

    cmpVariant<boost::variant<double, int>, double>(number, 3.2, equiv);
    

    这显然有点冗长,所以这里有另一种可能性,可以将函数声明更改为

    template<typename V, typename T, typename Fct = std::function<bool(const T& u, const T& v)>>
    bool cmpVariant(
        const V& variant,
        const T& t,
        Fct&& f = [](const T& u, const T& v) {return u == v; })
    { /* Same as before. */ }
    

    可以这样叫

    cmpVariant(number, 3.2, equiv); // Type deduction works now.
    

    @daniellangr在评论中提出的改进建议是 std::equal_to .

    template<typename V, typename T, typename Fct = std::equal_to<T>>
    bool cmpVariant(
          const V& variant,
          const T& t,
          Fct&& f = std::equal_to<T>{})
    { /* Again, same as before. */ }
    

    这里的一个优势是摆脱 std::function 而且经常是不必要的开销。

        2
  •  1
  •   user7860670    6 年前

    比较器参数被接受的方式会使推导出现问题,因此您可能希望将比较器更改为模板参数(可能避免构造 std::function 对象):

    template<typename T> class t_EquilityComparator
    {
        public: bool operator ()(const T& u, const T& v) const { return u == v; }
    };
    
    template<typename V, typename T, typename Comparator = t_EquilityComparator<T>>
    bool cmpVariant(
        const V& variant,
        const T& t,
        const Comparator & equiv = Comparator{})
    {
        if (variant.type() != typeid(t)) return false;
        auto v = boost::get<T>(variant);
        return equiv(v, t);
    }
    
    int main(int, char**) {
        boost::variant<double, int> number{ 3.2 };
        cmpVariant(number, 3.2);
        auto equiv = [](const double& x, const double& y) { return x == y; };
        cmpVariant(number, 3.2, equiv); // This line fails to compile! Why?
    }
    

    online compiler