【问题标题】:(g++ 4.7.1) Replacing explicit type name with an equivalent class typedef fails to compile(g++ 4.7.1) 用等效的类 typedef 替换显式类型名称无法编译
【发布时间】:2012-09-03 17:15:37
【问题描述】:

我正在尝试创建一个模板化函数,它接受一个可迭代和一个函数,这样传递的函数将被隐式转换为适当类型的 std::function(因此允许它与完整函数和lambda)。

代码如下:

#include <iostream>
#include <vector>
#include <algorithm>
#include <typeinfo>


template<typename T>
void bar(const T & base, std::function<bool(int)> f) // works
//void bar(const T & base, std::function<bool(typename T::iterator::value_type)> f) // fails to compile
{
    std::cout << ((typeid(std::function<bool(int)>) == typeid(std::function<bool(typename T::iterator::value_type)>))?"identical":"distinct") << std::endl;
}

bool filter(int x) { return x%2==0; }

int main() { bar(std::vector<int> {0, 1}, filter); }

使用g++-4.7 -std=c++11 -o itest itest.cpp 编译,生成identical

如果您取消注释第 10 行和注释第 9 行并按上述方式编译,则编译失败并显示

g++-4.7 -std=c++11 -Wall -Werror  -o itest itest.cpp
itest.cpp: In function 'int main()':
itest.cpp:16:53: error: no matching function for call to 'bar(std::vector<int>, bool (&)(int))'
itest.cpp:16:53: note: candidate is:
itest.cpp:9:10: note: template<class T> void bar(const T&, std::function<bool(typename T::iterator::value_type)>)
itest.cpp:9:10: note:   template argument deduction/substitution failed:
itest.cpp:16:53: note:   mismatched types 'std::function<bool(typename T::iterator::value_type)>' and 'bool (*)(int)'

我应该注意,未修改的版本在 Xcode 上成功(设置了适当的选项),但如果可能的话,我更愿意坚持使用 g++ 而不是 clang。我做错了什么,或者这是 g++ 中的一个已知错误?

【问题讨论】:

    标签: c++ templates c++11 g++


    【解决方案1】:

    抱歉,错误在您的代码中。相当于:

    template<typename T> struct S { template<typename U> S(const U &); };
    template<typename T> void bar(T, S<T>);
    int main() { bar(5, 6); }
    

    问题在于,在模板参数推导/替换中,如果模板参数(直接或在构造依赖类型中)出现在多个参数中,则两个参数必须完全匹配;不考虑用户定义的转换,即使从一个参数中可以明显看出类型必须是什么。

    这里的自定义转换是std::function&lt;...&gt;的隐式构造函数。

    可能的解决方法是显式实例化bar(如bar&lt;int&gt;),或分派给辅助函数:

    template<typename T>
    void bar_impl(const T & base, std::function<bool(typename T::iterator::value_type)> f)
    {
        std::cout << ((typeid(std::function<bool(int)>) == typeid(std::function<bool(typename T::iterator::value_type)>))?"identical":"distinct") << std::endl;
    }
    
    template<typename T, typename F>
    void bar(const T & base, F &&f)
    {
        bar_impl<T>(base, std::forward<F>(f));
    }
    

    【讨论】:

    • 嗯,谢谢。我已经实现了另一种(相当可怕的)解决方法,它不需要调用者引用或派生第二种类型。
    • 糟糕,忘记了link。对于不想同时阅读它的人来说,它本质上是在柯里化。
    【解决方案2】:

    指针函数需要第二个重载——然后它会编译。隐式转换为 std::function 不起作用:

    void bar(const T & base, bool(*f)(typename T::value_type)){
        std::cout << "ptr func\n";
    }
    

    解决 ecatmur 描述的问题(几个 T,函数signutre 中的类型不匹配):您可以将其他 T 包装在 identity 结构中,其定义如下:

    template<class T> struct identity{ typedef T type; };
    

    然后编译器将忽略这些 T 进行类型推导。

    【讨论】:

      猜你喜欢
      • 2012-08-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多