简体   繁体   English

C ++方法转发

[英]C++ method forwarding

I need to implement a class Container which acts exactly as the contained template class: 我需要实现一个类Container,其行为与包含的模板类完全相同:

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

T can be either a predefined type (eg, int ) or a user-defined type. T可以是预定义类型(例如, int )或用户定义类型。

The purpose is to intercept any read/write operations done on the contained type. 目的是拦截对包含类型执行的任何读/写操作。

I've succesfully implemented most operators, and it works. 我已成功实现了大多数运算符,并且它可以工作。

However, when I need to access methods specific of the contained class T, it doesn't work: 但是,当我需要访问特定于包含的类T的方法时,它不起作用:

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

The reason is that Container obviously doesn't have such methods. 原因是Container显然没有这样的方法。 Moreover, since T is a template, its methods cannot be known in advance. 此外,由于T是模板,因此无法预先知道其方法。

I guess there is no solution to this problem, even with C++11, because operator . 我想这个问题没有解决方案,即使使用C ++ 11,因为operator . cannot be overloaded. 不能超载。 Therefore, the only possible approach is to always rely on operator-> like smart pointers do. 因此,唯一可行的方法是始终依赖operator->像智能指针一样。

Can you confirm ? 你确定吗 ?

The C++ committee is currently looking into "overloaded operator . " for future revisions of the language. C ++委员会目前正在调查“重载operator . ”,以便将来修订该语言。

However, in your specific case, you can simply inherit from the type. 但是,在您的特定情况下,您可以简单地从类型继承。

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

For a class type T , this will act a lot like a T : 对于类类型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);}
};

for a non-class T , we detect it and use a different implementation: 对于非类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;}
};

finally, we go off and override every operator we can find in a SFINAE friendly way, where the operator only participates in overload resolution if get_t(Container) would work in its place in the operator. 最后,我们将以SFINAE友好的方式覆盖我们可以找到的每个运算符 ,如果get_t(Container)在运算符中的位置运行,则运算符仅参与重载get_t(Container) This should all be done in a namespace, so the operators are found via ADL. 这应该都在命名空间中完成,因此可以通过ADL找到运算符。 An overload of get_t that returns its argument unchanged could be useful to massively reduce the number of overloads. get_t的重载返回其参数不变可能有助于大量减少重载次数。

This could be another 100 or more lines of code. 这可能是另外100行或更多行代码。

Users of Container<T> can bypass the Container<T> and get the underlying T in the above system. Container<T>用户可以绕过Container<T>并获取上述系统中的底层T

Are you opposed to having a getter for the inner data member? 您是否反对为内部data成员提供getter? If no, then you can use something like this 如果不是,那么你可以使用这样的东西

#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();
}

Otherwise you could internally access the method, and it will only compile if such a method exists for T 否则你可以在内部访问该方法,只有在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();
}

So this latter method would work if T was eg std::string , std::vector , std::list , etc. 所以如果T是例如std::stringstd::vectorstd::list等,后一种方法就可以工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM