C ++ 11:根据容器的value_type进行Specialize / restrict方法

时间:2013-05-08 03:51:31

标签: c++ c++11 sfinae specialization

我有一个模板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 ++ 11模板工具的C::value_type的实际类型来专门化方法的行为?
  • 或者,是否有标准的方法来检查C实际上是否是容器?

感谢您的关注。

2 个答案:

答案 0 :(得分: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_typeaction_worker的第二个参数可以是ClassA*ClassB*。这将使编译器能够在您编写专用代码时选择正确的重载。

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

希望有所帮助。

答案 1 :(得分: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";
    }
};