【问题标题】:Failed to compile because of incompatible cv-qualifiers由于不兼容的 cv 限定符而无法编译
【发布时间】:2017-04-24 12:59:07
【问题描述】:

我有两个模板方法

template <typename T, typename Ret, typename ...Args>
Ret apply(T* object, Ret(T::*method)(Args...), Args&& ...args) {
    return (object->*method)(std::forward(args)...);
};

template <typename T, typename Ret, typename ...Args>
Ret apply(T* object, Ret(T::*method)(Args...) const, Args&& ...args) {
    return (object->*method)(std::forward(args)...);
};

我的目的是在这些 args

上应用 T 类的成员 method

这是我的测试代码:

int main() {
    using map_type = std::map<std::string, int>;
    map_type map;
    map.insert(std::make_pair("a", 1));
    std::cout << "Map size: " << apply(&map, &map_type::size) << std::endl; //this code work
    apply(&map, &map_type::insert, std::make_pair("a", 1)); //failed to compile

    return 0;
}

这是编译器错误信息:

    test.cpp: In function ‘int main()’:
test.cpp:61:58: error: no matching function for call to ‘apply(map_type*, <unresolved overloaded function type>, std::pair<const char*, int>)’
     apply(&map, &map_type::insert, std::make_pair("a", 1));
                                                          ^
test.cpp:11:5: note: candidate: template<class T, class Ret, class ... Args> Ret apply(T*, Ret (T::*)(Args ...), Args&& ...)
 Ret apply(T* object, Ret(T::*method)(Args...), Args&& ...args) {
     ^~~~~
test.cpp:11:5: note:   template argument deduction/substitution failed:
test.cpp:61:58: note:   couldn't deduce template parameter ‘Ret’
     apply(&map, &map_type::insert, std::make_pair("a", 1));

【问题讨论】:

标签: c++ templates type-deduction


【解决方案1】:

std::map::insert 是一个重载函数。除非您明确指定您感兴趣的重载,否则您无法获取它的地址 - 编译器怎么会知道?

解决您的问题的最简单方法是让apply 接受任意函数对象,并将您对insert 的调用包装在一个通用 lambda 中。 p>

template <typename F, typename ...Args>
decltype(auto) apply(F f, Args&& ...args) {
    return f(std::forward<Args>(args)...);
};

用法:

::apply([&](auto&&... xs) -> decltype(auto)
{ 
    return map.insert(std::forward<decltype(xs)>(xs)...);
}, std::make_pair("a", 1));

live wandbox example

不幸的是,额外的语法样板是不可避免的。这可能会在未来发生变化,请参阅:

  • N3617 旨在通过引入 "lift" 运算符来解决此问题

  • P0119 by A. Sutton 通过允许重载集在作为参数传递时基本上为您生成“包装器 lambda”,以不同的方式解决了这个问题。

我不确定上述提案是否支持重载的成员函数


您也可以通过在调用方显式指定您感兴趣的重载来使用原始解决方案:

::apply<map_type, std::pair<typename map_type::iterator, bool>,
        std::pair<const char* const, int>>(
    &map, &map_type::insert<std::pair<const char* const, int>>,
    std::make_pair("a", 1));

如您所见,它不是很漂亮。可以通过一些更好的模板参数推导来改进它,但不会太多。

【讨论】:

  • 我需要 f 是我的类的方法,我该如何指定它。对不起我的英语不好
  • @PhạmVănThông:你不能传递&amp;std::map::insert,因为你不能获取重载函数的地址,也不能在函数调用表达式之外引用它。你能做的最好的就是传递一个 lambda/function 对象,它将所有东西都转发给insert。您可以捕获地图实例,也可以将其作为额外参数传递给 lambda。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-07
  • 2020-01-17
  • 1970-01-01
  • 2023-03-12
  • 2018-06-27
  • 1970-01-01
相关资源
最近更新 更多