【问题标题】:C++ Function templates specialization for templated base class模板化基类的 C++ 函数模板特化
【发布时间】:2019-10-05 18:18:36
【问题描述】:

我正在尝试为模板类和所有派生子类实现成员函数模板特化。它适用于班级本身,但不适用于孩子。

请看以下演示问题的示例:

#include <vector>

struct MyVector : public std::vector<int> {};

struct S {
    template <typename T>
    int make(T value) {
        return 1;
    }

    template <typename T>
    int make(const std::vector<T>& value) {
        return 2;
    }
};

int main() {
    S s;
    // return s.make(std::vector<int>{}); // returns 2, perfekt!
    return s.make(MyVector{}); // returns 1 but should return 2
}

直播:https://godbolt.org/z/PgYkKf

我在 stackoverflow 上搜索了几个小时,但找不到合适的解决方案。我很感激任何提示!

【问题讨论】:

  • 从标准容器继承为std::vector? ……嗯……我对此有一种不好的预感。
  • 这只是为了演示目的.. 在实际代码中没有这样做:)

标签: c++ sfinae template-specialization


【解决方案1】:

函数模板特化

第一笔生意。这不是专业。重要的是要解决这个问题。这是超载。这两个函数模板重载了make 名称。重载决议在综合他们的签名后确定哪个是更好的匹配。在您的情况下,编译器可以推断出的两个签名是

int make(MyVector);
int make(std::vector<int> const&);

一个是身份转换,而另一个需要绑定对基的引用,就转换而言,它的排名比“身份”差。所以选择了第一个重载。

您有几个选择:

  1. 首选类型别名,如using MyVector = std::vector&lt;int&gt;;。它是直接的,完全匹配第二个重载,并且由于函数模板的部分排序而使其被选中。

  2. 添加一个MyVector 重载,代表:

    int make(MyVector const& v) { return make(static_cast<MyVector::vector const&>(v)); }
    
  3. 使用更复杂的技术来控制重载分辨率。标准库有一些用于基于SFINAE 的过程控制的实用程序。这需要将第一个重载更改为:

    template <typename T>
    std::enable_if_t<!std::is_convertible_v<T*, std::vector<int>*>, int>
    make(T value) {
        return 1;
    }
    

    但是这种方法对专家来说过于友好,并且很快就无法随着许多模板重载而扩展。我首先推荐前两种方法。

【讨论】:

  • 感谢您的解释!遗憾的是,选项 1 和 2 对我不起作用,因为很多类都派生自模板基类并实现了额外的成员函数。以下示例更好地捕捉了真实用例:godbolt.org/z/lPk03P。还有其他可能吗?也许为那些使用辅助结构和模板专业化?
猜你喜欢
  • 2011-06-27
  • 1970-01-01
  • 1970-01-01
  • 2021-04-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多