【问题标题】:Specializing a method template for classes in a namespace为命名空间中的类专门化方法模板
【发布时间】:2012-01-25 17:53:00
【问题描述】:

我正在使用以下编译时“技巧”(基于 ADL)来创建一个仅由同一命名空间中的类有效/定义/可调用的函数。

    namespace Family1
    {
        struct ModelA{};
        struct ModelB{};

        template<typename T>
        bool is_in_Family1(T const& t) 
        {
            return true;
        }
    };

    namespace Family2
    {
        struct ModelC{};

        template<typename T>
        bool is_in_Family2(T const& t) 
        {
            return true;
        }
    };


    Family1::ModelA mA;
    Family2::ModelC mC;

    is_in_Family1(mA);          // VALID
    is_in_Family1(mC);          // ERROR

现在,我想使用这个原则(或类似的东西)来为属于每个命名空间的类生成一个专门化的 Foo::Bar(如下),例如Family1

    // I would like to specialize the method template Bar for classes in Family1 
    // namespace; and another specialization for classes in Family2 namespace
    struct Foo
    {
        template<typename T>
        void Bar( T& _T ){}
    };

为了便于维护和每个命名空间中的大量类,如果可能,我想在不命名命名空间中的所有类的情况下执行此检查。

【问题讨论】:

  • 为什么Foo是一个模板类,它的构造函数也是一个不同类型的模板? Foo&lt;float&gt; myvar('4');?您只是想拥有一个template&lt;typename T&gt; 吗?因为没有使用外部的。如果Foo 只是一个函数,我认为这可以做到,但我认为它不能用于结构。或者至少,不是很好。

标签: c++ templates sfinae


【解决方案1】:

你的“把戏”有一个大问题。尝试调用is_in_Family1(make_pair(Family1::ModelA(), Family2::ModelC()),您将看到返回true,因为ADL 将同时查看ModelAModelC 的命名空间(因为pair&lt;ModelA, ModelC&gt;)。

忽略这个问题,使用你的函数是直截了当的。

template<typename T> struct int_ { typedef int type; };

struct Foo
{
    template<typename T, 
             typename int_<decltype(is_in_Family1(*(T*)0))>::type = 0
    >
    void Bar( T& t ){}

    template<typename T, 
             typename int_<decltype(is_in_Family2(*(T*)0))>::type = 0
    >
    void Bar( T& t ){}
};

这会调用Bar,具体取决于它是在family2还是family1中。

struct Foo
{
    template<typename T, 
             typename int_<decltype(is_in_Family1(*(T*)0))>::type = 0
    >
    void Bar( T& t, long){}

    template<typename T,
             typename int_<decltype(is_in_Family2(*(T*)0))>::type = 0
    >
    void Bar( T& t, long){}

    template<typename T>
    void Bar( T& t, int) {}

    template<typename T>
    void Bar( T& t ) { return Bar(t, 0); }
};

那个也有一个通用的后备。而且您的代码具有未定义的行为,因为您使用了保留名称。不要使用_T

【讨论】:

  • 谢谢@litb! (我目前正在研究您的答案。)除了让is_in_Family 返回布尔值之外,还有其他选择吗?再说一次,为什么一对是is_in_Family 的有效参数?
  • @olu 不知道关于 alrernatives。这是一个有效的参数,因为您将其设为模板,因此它可以接受任何内容。
【解决方案2】:

我发现最快的方法是使用 Boost Type Traits 的 is_base_of

我尝试将继承与模板特化一起使用,但这不起作用,因为在使用模板特化时会忽略继承,因此您必须针对每个模型进行特化。 Partial specialization for a parent of multiple classes 的答案说明了问题。

如果您使 Family1::ModelA 和 Family::ModelB 成为 Family1:Family1Type 的子类和 Family2::ModelC 成为 Family2::Family2Type 的子类,则使用类型特征有效:

#include <iostream>
#include <boost/type_traits/is_base_of.hpp>

namespace Family1{

    struct Family1Type{};

    struct ModelA :public Family1Type{};
    struct ModelB :public Family1Type{};

    template<typename T>
    bool is_in_Family1(const T& t){
        return boost::is_base_of<Family1::Family1Type,T>::value;
    }
};

namespace Family2{
    struct Family2Type{};

    struct ModelC :public Family2Type{};

    template<typename T>
    bool is_in_Family2(const T& t){
        return boost::is_base_of<Family2::Family2Type,T>::value;
    }

};

using namespace std;
int main(int argc, char *argv[]) {

    Family1::ModelA mA;
    Family2::ModelC mC;

    std::cout << "mA is in Family1?  " << is_in_Family1(mA) << std::endl;
    std::cout << "mC is in Family2?  " << is_in_Family2(mC) << std::endl;

    //std::cout << "mC is in Family1?  " << is_in_Family1(mC) << std::endl; //ERROR!
    //std::cout << "mA is in Family2?  " << is_in_Family2(mA) << std::endl; //ERROR!

    return 0;
}

这会产生以下输出:

mA is in Family1?  1
mC is in Family2?  1

我认为没有办法根据Specialization of 'template<class _Tp> struct std::less' in different namespace声明Foo并在另一个命名空间中专门化Foo::Bar&lt;&gt;

【讨论】:

  • 谢谢@Joel。 Foo 对每个命名空间的特化怎么样?
  • 从头开始。我真正想做的是为每个命名空间专门化一个 Foo 方法。我已经相应地编辑了我的帖子。
  • @Olumide 如果不在每个命名空间中声明 Foo 结构,我目前似乎无法弄清楚如何做到这一点。我似乎无法在我实现它的专业化的命名空间之外定义 Foo。
猜你喜欢
  • 1970-01-01
  • 2013-04-09
  • 2016-12-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-08
  • 1970-01-01
  • 2014-02-06
相关资源
最近更新 更多