3

我有一个action接受任何类型的 STL 容器的模板方法C。但是,包含的项目 ( C::value_type) 必须是ClassAClassB。到目前为止,一切都很好:

struct Whatever {
    template<typename C>
    void action(const C& c) {
        static_assert(std::is_same<typename C::value_type, ClassA>::value ||
                      std::is_same<typename C::value_type, ClassB>::value,
                      "Wrong C::value_type");
        // do something with c
    }
};

// Usage:
Whatever w;
w.action(std::vector<ClassA>{1, 2, 3});
w.action(std::unordered_set<ClassB>{1, 2, 3});

注意:封闭类不是模板,唯一的模板就是这个action方法。

现在,根据C::value_type,我想专门研究该方法的行为。你猜对了,这就是我的大脑开始融化的地方。


我相信 SFINAE 是要走的路,但显然我太生疏了,无法让它正常工作:几个小时后,大量的助手structs和太多的咖啡对我自己的健康不利,编译器只是不停地大喊通常的 500 多个模板错误我。复制我的助手structs或这里的错误毫无意义,这几乎是无用的垃圾。

然而,我不得不承认,自从十年以来,我并没有真正接触过所有的 C++ 模板 (r) 演变(或者甚至使用 SFINAE),所以难怪我会如此失败。

我强烈怀疑 C++11 现在有简单、易于使用的类似 SFINAE 的工具来实现我想要的,但我什至不知道从哪里开始在文档中搜索。搜索引擎也没有帮助,一次有太多新信息让我无法理解与我的问题相关/不相关的内容。

由于我完全不知所措,我只会采取婴儿步骤并问...我的问题有两个:

  • 如何根据C::value_type使用现代 C++11 模板工具的实际类型来专门化该方法的行为?
  • 或者,是否有标准方法来检查是否C真的是一个容器?

感谢您的关注。

4

2 回答 2

3

我想知道你为什么不这样做:

 template<typename C>
 void action(const C& c) 
 {
        static_assert(std::is_same<typename C::value_type, ClassA>::value ||
                      std::is_same<typename C::value_type, ClassB>::value,
                      "Wrong C::value_type");

      action_worker(c, static_cast<typename C::value_type*>(0));
 }

private:

 template<typename C>
 void action_worker(const C& c, ClassA *) 
 {
     //specialized code when C::value_type is ClassA
 }

 template<typename C>
 void action_worker(const C& c, ClassB *) 
 {
     //specialized code when C::value_type is ClassB
 }

现在取决于C::value_type, to 的第二个参数action_worker可以是ClassA*or ClassB*。这将使编译器能够在您编写专用代码的地方选择正确的重载。

对于您问题的第二部分,请参阅is_container此答案中类模板的实现:

希望有帮助。

于 2013-05-08T04:12:39.483 回答
1

由于您只支持这两种类型,我会考虑使用 enable_if:

struct Whatever
{
    template<typename C>
    typename std::enable_if<std::is_same<typename C::value_type, ClassA>::value, void>::type
    action(const C& c)
    {
        std::cout << "ClassA\n";
    }

    template<typename C>
    typename std::enable_if<std::is_same<typename C::value_type, ClassB>::value, void>::type
    action(const C& c)
    {
        std::cout << "ClassB\n";
    }
};
于 2013-05-08T07:37:37.950 回答