模板元代码和私有成员
Template meta-code and private members
我想做这样的事情:
template <typename T>
class Foo
{
...
public:
void DoSomething()
{
compile_time_if (T is ClassA)
{
m_T.DoThingOne();
m_T.DoThingTwo();
}
DoSomeFooPrivateThing();
m_T.DoThingThree();
}
T m_T;
};
在这种情况下,我知道所有有效的 T
都实现了 DoThingThree
,但只有 ClassA
实现了 DoThingOne
和 DoThingTwo
。这不是鸭子打字的事情,我只想为 ClassA
做这个额外的部分,我不想将这些方法添加到其他可能的 T
s。我无法进行转换,因为可能的 T
不是继承类型。
我知道我可以使用外部助手模板来适应这个:
template <typename T>
void Foo_DoSomething(T& t)
{
t.DoThingThree();
}
template <>
void Foo_DoSomething(ClassA& t)
{
t.DoThingOne();
t.DoThingTwo();
t.DoThingThree();
}
template <typename T>
class Foo
{
...
public:
void DoSomething()
{
Foo_DoSomething(m_T);
}
...
};
但是现在这个外部模板无法访问Foo
的私有成员(不能调用DoSomeFooPrivateThing
),这限制了它的功能,而且它是公开暴露在外面的,这不漂亮。 (让外部方法成为朋友只会让事情变得更糟。)
另一个看似合理的选择是在内部实现它:
template <typename T>
class Foo
{
...
public:
void DoSomething()
{
DoSomethingImpl(m_T);
}
...
private:
template <typename T2>
void DoSomethingImpl(T2& t)
{
DoSomeFooPrivateThing();
t.DoThingThree();
}
template <>
void DoSomethingImpl(ClassA& t)
{
t.DoThingOne();
t.DoThingTwo();
DoSomeFooPrivateThing();
t.DoThingThree();
}
...
};
但这需要复制外部模板类型和参数。这可能是可以接受的,但仍然感觉有点奇怪。遗憾的是它实际上并没有编译(至少在 GCC 中没有,因为它反对 类 内的专业化)。
有更好的方法吗?
我认为你最后的选择是最好的。
而不是
template <>
void DoSomethingImpl(ClassA& t)
{
t.DoThingOne();
t.DoThingTwo();
DoSomeFooPrivateThing();
t.DoThingThree();
}
你可以直接使用(这里不需要使用template
):
void DoSomethingImpl(ClassA& t)
{
t.DoThingOne();
t.DoThingTwo();
DoSomeFooPrivateThing();
t.DoThingThree();
}
第一个解决方案:如你所说,我们可以这样做:
template <typename T> class Foo{
public:
void doSomething(){
doSomething(std::is_same<T,A>());
}
private:
void doSomething(std::true_type){
cout<<"A do"<<endl;
}
void doSomething(std::false_type){
cout<<"any other do"<<endl;
}
};
第二种方案:
因为模板 class Foo 只有一个模板参数,所以我们可以直接像这样显式特化。
template <typename T> class Foo{
public:
void doSomething(){
cout<<"any other do..."<<endl;
}
};
template<> void Foo<A>::doSomething(){
cout<<"A do"<<endl;
}
第三种解法:
也许不是一个好方法,我们可以这样做,
这样(SFINAE)使用 C++11 或 boost enable_if.When 类型与 A 相同,compiler auto select expected class.
#include <iostream>
using namespace std;
class A {};
template <typename T,typename Enable = void>
class Foo
{
public:
void DoSomething()
{
cout<<"anyother do"<<endl;
}
private:
T m_T;
};
template <typename T> class Foo<T, typename enable_if<is_same<T,A>::value>::type >
{
public:
void DoSomething()
{
cout<<"A do"<<endl;
}
private:
T m_T;
};
更多:
如果两个 Foo 有很多相同的东西,我们可以像这样为它创建基 class:
template <typename T> class BaseFoo{
...
};
和两个从 BaseFoo 派生的模板 class,如下所示:
template <typename T,typename Enable = void>
class Foo:public BaseFoo<T>{...}
template <typename T> class Foo<T, typename enable_if
<is_same<T,A>::value>::type >:public BaseFoo<T>{...}
我已经习惯了你最后的解决方案,所以我觉得它并不奇怪。
如果你愿意,你可以随时做
void DoSomethingImpl(T&t, std::true_type){...}
和
void DoSomethingImpl(T&t, std::false_type){...}
然后
DoSomethingImpl(m_T, std::is_same<T, ClassA>{});
这在功能上是等效的,但如果需要扩展功能,还允许进行更复杂的决策。
我想做这样的事情:
template <typename T>
class Foo
{
...
public:
void DoSomething()
{
compile_time_if (T is ClassA)
{
m_T.DoThingOne();
m_T.DoThingTwo();
}
DoSomeFooPrivateThing();
m_T.DoThingThree();
}
T m_T;
};
在这种情况下,我知道所有有效的 T
都实现了 DoThingThree
,但只有 ClassA
实现了 DoThingOne
和 DoThingTwo
。这不是鸭子打字的事情,我只想为 ClassA
做这个额外的部分,我不想将这些方法添加到其他可能的 T
s。我无法进行转换,因为可能的 T
不是继承类型。
我知道我可以使用外部助手模板来适应这个:
template <typename T>
void Foo_DoSomething(T& t)
{
t.DoThingThree();
}
template <>
void Foo_DoSomething(ClassA& t)
{
t.DoThingOne();
t.DoThingTwo();
t.DoThingThree();
}
template <typename T>
class Foo
{
...
public:
void DoSomething()
{
Foo_DoSomething(m_T);
}
...
};
但是现在这个外部模板无法访问Foo
的私有成员(不能调用DoSomeFooPrivateThing
),这限制了它的功能,而且它是公开暴露在外面的,这不漂亮。 (让外部方法成为朋友只会让事情变得更糟。)
另一个看似合理的选择是在内部实现它:
template <typename T>
class Foo
{
...
public:
void DoSomething()
{
DoSomethingImpl(m_T);
}
...
private:
template <typename T2>
void DoSomethingImpl(T2& t)
{
DoSomeFooPrivateThing();
t.DoThingThree();
}
template <>
void DoSomethingImpl(ClassA& t)
{
t.DoThingOne();
t.DoThingTwo();
DoSomeFooPrivateThing();
t.DoThingThree();
}
...
};
但这需要复制外部模板类型和参数。这可能是可以接受的,但仍然感觉有点奇怪。遗憾的是它实际上并没有编译(至少在 GCC 中没有,因为它反对 类 内的专业化)。
有更好的方法吗?
我认为你最后的选择是最好的。
而不是
template <>
void DoSomethingImpl(ClassA& t)
{
t.DoThingOne();
t.DoThingTwo();
DoSomeFooPrivateThing();
t.DoThingThree();
}
你可以直接使用(这里不需要使用template
):
void DoSomethingImpl(ClassA& t)
{
t.DoThingOne();
t.DoThingTwo();
DoSomeFooPrivateThing();
t.DoThingThree();
}
第一个解决方案:如你所说,我们可以这样做:
template <typename T> class Foo{
public:
void doSomething(){
doSomething(std::is_same<T,A>());
}
private:
void doSomething(std::true_type){
cout<<"A do"<<endl;
}
void doSomething(std::false_type){
cout<<"any other do"<<endl;
}
};
第二种方案: 因为模板 class Foo 只有一个模板参数,所以我们可以直接像这样显式特化。
template <typename T> class Foo{
public:
void doSomething(){
cout<<"any other do..."<<endl;
}
};
template<> void Foo<A>::doSomething(){
cout<<"A do"<<endl;
}
第三种解法: 也许不是一个好方法,我们可以这样做, 这样(SFINAE)使用 C++11 或 boost enable_if.When 类型与 A 相同,compiler auto select expected class.
#include <iostream>
using namespace std;
class A {};
template <typename T,typename Enable = void>
class Foo
{
public:
void DoSomething()
{
cout<<"anyother do"<<endl;
}
private:
T m_T;
};
template <typename T> class Foo<T, typename enable_if<is_same<T,A>::value>::type >
{
public:
void DoSomething()
{
cout<<"A do"<<endl;
}
private:
T m_T;
};
更多:
如果两个 Foo 有很多相同的东西,我们可以像这样为它创建基 class:
template <typename T> class BaseFoo{
...
};
和两个从 BaseFoo 派生的模板 class,如下所示:
template <typename T,typename Enable = void>
class Foo:public BaseFoo<T>{...}
template <typename T> class Foo<T, typename enable_if
<is_same<T,A>::value>::type >:public BaseFoo<T>{...}
我已经习惯了你最后的解决方案,所以我觉得它并不奇怪。
如果你愿意,你可以随时做
void DoSomethingImpl(T&t, std::true_type){...}
和
void DoSomethingImpl(T&t, std::false_type){...}
然后
DoSomethingImpl(m_T, std::is_same<T, ClassA>{});
这在功能上是等效的,但如果需要扩展功能,还允许进行更复杂的决策。