C ++方法转发

时间:2015-06-12 12:25:16

标签: c++ templates c++11 operator-overloading perfect-forwarding

我需要实现一个类Container,其行为与包含的模板类完全相同:

template <typename T>
class Container {
public:
      //...
private:
      // T data_;
};

T可以是预定义类型(例如int)或用户定义类型。

目的是拦截对包含类型所做的任何读/写操作。

我已经成功实施了大多数运营商,并且运作良好。

但是,当我需要访问特定于包含的类T的方法时,它不起作用:

Container<myclass> a;
a.myclass_specific_method();

原因是Container显然没有这样的方法。此外,由于T是模板,因此无法事先知道其方法。

我想即使使用C ++ 11也无法解决此问题,因为operator .无法重载。因此,唯一可行的方法是始终依赖operator->智能指针。

你能证实吗?

3 个答案:

答案 0 :(得分:13)

C ++委员会目前正在研究过度operator .&#34;对于该语言的未来修订。

但是,在您的特定情况下,您可以直接从类型继承。

template <typename T>
class Container : private T {
public:
    using T::something_publicly_accessible;
};

答案 1 :(得分:2)

对于类型T,这会像T一样:

template<class T, class=void>
struct Container : public T { // inheritance MUST be public
  using T::T;
  Container() = default; // or override
  Container( Container const& ) = default; // or override
  Container( Container && ) = default; // or override
  Container& operator=( Container const& ) = default; // or override
  Container& operator=( Container && ) = default; // or override
  // here, we override any method we want to intercept

  // these are used by operators:
  friend T& get_t(Container& self){return self;}
  friend T const& get_t(Container const& self){return self;}
  friend T&& get_t(Container&& self){return std::move(self);}
  friend T const&& get_t(Container const&& self){return std::move(self);}
};

对于非类T,我们会检测它并使用不同的实现:

template<class T>
struct Container<T, typename std::enable_if<!std::is_class<T>{}>::type > {
  T t;
  Container() = default; // or override
  Container( Container const& ) = default; // or override
  Container( Container && ) = default; // or override
  Container& operator=( Container const& ) = default; // or override
  Container& operator=( Container && ) = default; // or override

  // these are used by operators:
  friend T& get_t(Container& self){return self.t;}
  friend T const& get_t(Container const& self){return self.t;}
  friend T&& get_t(Container&& self){return std::move(self).t;}
  friend T const&& get_t(Container const&& self){return std::move(self).t;}
};

最后,我们以SFINAE友好的方式关闭我们能找到的每个操作符,其中如果get_t(Container)在运算符中的位置,运算符只参与重载解析。这应该都在命名空间中完成,因此可以通过ADL找到运算符。 get_t的重载返回其参数不变可能有助于大量减少重载次数。

这可能是另外100行或更多行代码。

Container<T>的用户可以绕过Container<T>并获取上述系统中的基础T

答案 2 :(得分:1)

您是否反对为内部data成员获取吸气剂?如果不是,那么你可以使用这样的东西

#include <iostream>
#include <string>

template <typename T>
class Container
{
public:
    Container(T _data) : data{_data} {}
    T GetData() const { return data; }
private:
    T data;
};

int main()
{
    Container<std::string> c{"foo"};
    std::cout << c.GetData().size();
}

否则你可以在内部访问该方法,只有在T

存在这种方法时才能编译
#include <iostream>
#include <string>

template <typename T>
class Container
{
public:
    Container(T _data) : data{_data} {}
    std::size_t size() const { return data.size(); }
private:
    T data;
};

int main()
{
    Container<std::string> c{"foo"};
    std::cout << c.size();
}

如果T是例如,那么后一种方法就可行std::stringstd::vectorstd::list