如何为所有引用类型特化 类 C++03
How to specialize classes for all reference types C++03
请注意 C++03 是我真正需要的,但为了知识的缘故,我也希望在 C++11 中看到一些更漂亮的实现。
我需要一个模板class
template <typename T>
class A {
private:
T m_member;
public:
A(T _member);
//... MORE STUFF
void foo(T param);
};
我需要:
1) 如果 A 是用值类型编译的(包括指针,它们本身是按值传递的):
然后我需要A看起来像这样(和上面一模一样)
class A {
private:
T m_member;
public:
A(T _member);
//... MORE STUFF
void foo(T param);
};
2) 如果A是用引用类型编译的(比如int&
):
然后我需要A看起来像这样:
class A{
private:
T& m_member;
public:
A(T& _member);
//... MORE STUFF
void foo(T param); // still the same T, not T&
};
如果我知道 A 只接收整数,那么我就可以使用特化。
但是A的用户可以使用任何类型:
main.cpp
A<int> a1;//1st version
A<int&> a2;//2nd version
A<B> a3;//1st version
A<B&> a4;//2nd version
A<C*> a5;//1st version
如本帖 Specializing function template for reference types 中所见(正确),此处建议的 remove_reference 将不起作用。它永远不会进入第二个实现,因为编译器认为 T& 和 T 是一样的。
相反,您可以使用相同的专业化技巧手动告诉编译器它现在正在处理引用类型
template<typename T, bool isReference>
class A {
};
template<typename T>
class A<T,false>{
private:
T m_member;
public:
A(T _member);
//... MORE STUFF
void foo(T param);
}
/////////////////////////
template<typename T>
class A<T,true>{
private:
T& m_member;
public:
A(T& _member);
//... MORE STUFF
void foo(T param);
}
如果您想提取一些类似的行为并避免此解决方案导致的代码重复,您可以轻松地将该行为提取到基 Class<T>
,然后执行
template<typename T,bool isReference>
class A : public BaseClass<T>{
}
等等。
用法是
main.cpp
A<int,false> a1;//1st version
A<int&,true> a2;//2nd version
A<B,false> a3;//1st version
A<B&,true> a4;//2nd version
A<C*,false> a5;//1st version, as pointers are value types
注意: 此答案中的想法归功于 n.m。
为了使您的想法可行,您只需将 foo
的函数参数类型设置为始终为非引用类型。在 C++11 中有一个名为 std::remove_reference
的辅助函数模板,但在 C++03 中可以轻松实现。示例代码:
#include <iostream>
template<typename T> struct remove_reference {typedef T type;};
template<typename T> struct remove_reference<T&> {typedef T type;};
template<typename T>
class A{
private:
T m_member;
public:
A(T m): m_member(m) {}
void foo(typename remove_reference<T>::type param) { param = 0; }
};
struct B { int x; B(int x): x(x) {} };
struct C {};
int main()
{
int a = 1;
A<int> a1(a);
A<int&> a2(a);
a1.foo(a); std::cout << a << std::endl;
a2.foo(a); std::cout << a << std::endl;
B b(1);
A<B> b1(b);
A<B&> b2(b);
b1.foo(b); std::cout << b.x << std::endl;
b2.foo(b); std::cout << b.x << std::endl;
C c;
A<C*> c1(&c);
c1.foo(&c);
}
输出:
$ g++ -o r r.cc -std=c++03 && ./r
1
1
1
1
如您所见,1
输出表明参数是按值传递的(因此 param = 0
正在更改本地副本,而不是作为参数给出的对象)。
另一种验证代码是否按预期工作的方法是在 foo
中输出 gcc 扩展 __PRETTY_FUNCTION__
。调用 a2.foo(a);
的那一行的输出是:
void A<T>::foo(typename remove_reference<T>::type) [with T = int&; typename remove_reference<T>::type = int]
请注意 C++03 是我真正需要的,但为了知识的缘故,我也希望在 C++11 中看到一些更漂亮的实现。
我需要一个模板class
template <typename T>
class A {
private:
T m_member;
public:
A(T _member);
//... MORE STUFF
void foo(T param);
};
我需要:
1) 如果 A 是用值类型编译的(包括指针,它们本身是按值传递的):
然后我需要A看起来像这样(和上面一模一样)
class A {
private:
T m_member;
public:
A(T _member);
//... MORE STUFF
void foo(T param);
};
2) 如果A是用引用类型编译的(比如int&
):
然后我需要A看起来像这样:
class A{
private:
T& m_member;
public:
A(T& _member);
//... MORE STUFF
void foo(T param); // still the same T, not T&
};
如果我知道 A 只接收整数,那么我就可以使用特化。 但是A的用户可以使用任何类型:
main.cpp
A<int> a1;//1st version
A<int&> a2;//2nd version
A<B> a3;//1st version
A<B&> a4;//2nd version
A<C*> a5;//1st version
如本帖 Specializing function template for reference types 中所见(正确),此处建议的 remove_reference 将不起作用。它永远不会进入第二个实现,因为编译器认为 T& 和 T 是一样的。
相反,您可以使用相同的专业化技巧手动告诉编译器它现在正在处理引用类型
template<typename T, bool isReference>
class A {
};
template<typename T>
class A<T,false>{
private:
T m_member;
public:
A(T _member);
//... MORE STUFF
void foo(T param);
}
/////////////////////////
template<typename T>
class A<T,true>{
private:
T& m_member;
public:
A(T& _member);
//... MORE STUFF
void foo(T param);
}
如果您想提取一些类似的行为并避免此解决方案导致的代码重复,您可以轻松地将该行为提取到基 Class<T>
,然后执行
template<typename T,bool isReference>
class A : public BaseClass<T>{
}
等等。
用法是
main.cpp
A<int,false> a1;//1st version
A<int&,true> a2;//2nd version
A<B,false> a3;//1st version
A<B&,true> a4;//2nd version
A<C*,false> a5;//1st version, as pointers are value types
注意: 此答案中的想法归功于 n.m。
为了使您的想法可行,您只需将 foo
的函数参数类型设置为始终为非引用类型。在 C++11 中有一个名为 std::remove_reference
的辅助函数模板,但在 C++03 中可以轻松实现。示例代码:
#include <iostream>
template<typename T> struct remove_reference {typedef T type;};
template<typename T> struct remove_reference<T&> {typedef T type;};
template<typename T>
class A{
private:
T m_member;
public:
A(T m): m_member(m) {}
void foo(typename remove_reference<T>::type param) { param = 0; }
};
struct B { int x; B(int x): x(x) {} };
struct C {};
int main()
{
int a = 1;
A<int> a1(a);
A<int&> a2(a);
a1.foo(a); std::cout << a << std::endl;
a2.foo(a); std::cout << a << std::endl;
B b(1);
A<B> b1(b);
A<B&> b2(b);
b1.foo(b); std::cout << b.x << std::endl;
b2.foo(b); std::cout << b.x << std::endl;
C c;
A<C*> c1(&c);
c1.foo(&c);
}
输出:
$ g++ -o r r.cc -std=c++03 && ./r
1
1
1
1
如您所见,1
输出表明参数是按值传递的(因此 param = 0
正在更改本地副本,而不是作为参数给出的对象)。
另一种验证代码是否按预期工作的方法是在 foo
中输出 gcc 扩展 __PRETTY_FUNCTION__
。调用 a2.foo(a);
的那一行的输出是:
void A<T>::foo(typename remove_reference<T>::type) [with T = int&; typename remove_reference<T>::type = int]