如何为所有引用类型专门化类

How to specialize classes for all reference types C++03

本文关键字:引用类型 专门化      更新时间:2023-10-16

请注意c++ 03是我真正需要的,但为了知识起见,我希望在c++ 11中看到一些更漂亮的实现。

我需要一个模板类
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只接收int型,那么我就可以使用专门化。但是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

在这个线程专门化函数模板中可以看到(正确地),这里建议的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);
}

如果您想提取一些类似的行为并避免此解决方案导致的代码重复,您可以轻松地将该行为提取到Base 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的输出表明参数是通过value传递的(因此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]