我正在使用以下编译时'技巧'(基于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 ){}
};
为了便于维护和每个命名空间中的大量类,如果可能的话,我想在不命名命名空间中的所有类的情况下执行此检查。
答案 0 :(得分:1)
你的“诡计”有一个大问题。尝试调用is_in_Family1(make_pair(Family1::ModelA(), Family2::ModelC())
,您会看到返回true
,因为ADL会同时查看ModelA
和ModelC
的命名空间(因为pair<ModelA, ModelC>
)。< / p>
忽略这个问题,使用你的功能很简单。
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 ){}
};
根据它是在family2还是family1中调用Bar
。
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
。
答案 1 :(得分:0)
我发现这样做最快的方法是使用Boost Type Traits'is_base_of&lt;&gt;
我尝试将继承与模板特化一起使用,但是这不起作用,因为在使用模板特化时会忽略继承,因此您必须专门针对每个模型。 Partial specialization for a parent of multiple classes的答案解释了这个问题。
使用类型特征工作,只要你将Family1:Family1Type和Family2 :: FamilyC的Family1 :: ModelA和Family :: ModelB子类作为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<>