用于提供正确的类似指针的行为(指向常量的指针)的替代类设计?

发布于 2024-12-16 21:42:07 字数 1482 浏览 1 评论 0原文

我正在编写一组 C++ 参数化类,我对其中一些与指针类似的行为感兴趣。特别是,我希望能够从具有非常量模板参数的对象创建具有常量模板参数的对象,但反之则不然。这个示例代码应该澄清我的意图:

int main() {
  myClass<int> mc_int;
  myClass<const int> mc_const_int;

  myClass<const int> mc1(mc_const_int); // This should compile.
  myClass<int> mc2(mc_int);             // This should compile.
  myClass<const int> mc3(mc_int);       // This should compile.
  myClass<int> mc4(mc_const_int);       // This should NOT compile.
}

我已经能够通过创建下一个类层次结构(为了可读性而简化)来实现这个特定的行为:

template <typename T>
class Base {

  // ...

protected:

  template <typename U>
  Base(const Base<U> &obj): _elem(obj._elem) {}

private:

  T _elem;

  friend class Base<const T>;
};

template <typename T>
class myClass: public Base<T> {

  // ...

public:

  template <typename U>
  myClass(const myClass<U> &obj): Base<const U>(obj) {}
};

并且它按预期工作,但我对这个设计并不完全满意,因为我只能检测来自构造函数的非常量模板参数,但不来自任何其他成员函数。

例如,如果我想创建一个带有 addAll() 方法的容器类,我希望能够做到这一点:

int main() {
  Container<int> c_int;

  c_int.add(new int(1));
  c_int.add(new int(2));
  c_int.add(new int(3));

  Container<const int> c_const_int;

  c_const_int.addAll(c_int); // This should compile.
  c_int.addAll(c_const_int); // This should NOT compile.
}

但我不知道如何实现前面的行为。有谁有替代设计的想法来实现我想要做的事情?有谁知道更深入讨论这个问题的链接?

提前致谢。

I'm writing a set of C++ parameterized classes and I'm interested in some of them behaving similarly to pointers. In particular, I want to be able to create an object with a constant template parameter from an object with a non-constant template parameter, but not the other way around. This sample code should clarify my intentions:

int main() {
  myClass<int> mc_int;
  myClass<const int> mc_const_int;

  myClass<const int> mc1(mc_const_int); // This should compile.
  myClass<int> mc2(mc_int);             // This should compile.
  myClass<const int> mc3(mc_int);       // This should compile.
  myClass<int> mc4(mc_const_int);       // This should NOT compile.
}

I have been able to achieve this particular behavior by creating the next class hierarchy (simplified for readability):

template <typename T>
class Base {

  // ...

protected:

  template <typename U>
  Base(const Base<U> &obj): _elem(obj._elem) {}

private:

  T _elem;

  friend class Base<const T>;
};

template <typename T>
class myClass: public Base<T> {

  // ...

public:

  template <typename U>
  myClass(const myClass<U> &obj): Base<const U>(obj) {}
};

And it works as expected, but I'm not entirely satisfied with this design because I can only detect a non-constant template parameter from the constructor, but not from any other member function.

If I wanted, for example, to create a container class with an addAll() method, I would like to be able to do this:

int main() {
  Container<int> c_int;

  c_int.add(new int(1));
  c_int.add(new int(2));
  c_int.add(new int(3));

  Container<const int> c_const_int;

  c_const_int.addAll(c_int); // This should compile.
  c_int.addAll(c_const_int); // This should NOT compile.
}

But I don't know how to achieve the previous behavior. Does anyone have ideas for an alternate design to achieve what I'm trying to do? Does anyone know of a link where this problem is discussed in more depth?

Thanks in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

耳钉梦 2024-12-23 21:42:08

一种可能性是使用成员函数模板,使它们能够实现您想要的组合。

#include <utility>

template <class T, class U>
struct const_convertible;

template <class T>
struct const_convertible<T, T>: std::true_type {};

template <class T>
struct const_convertible<T, const T>: std::true_type {};

template <class T>
struct const_convertible<const T, T>: std::false_type {};

template <class T>
class X
{
public:
   X() {}
   X(const X&) {} //copy constructor
   //conversion constructor as needed
   template <class U>
   X(const X<U>&, typename std::enable_if<const_convertible<U, T>::value, void>::type* = 0)
   {}

   template <class U>
   typename std::enable_if<const_convertible<U, T>::value, void>::type f(X<U>) {}
};

int main()
{
   X<int> mut;
   X<const int> con;

   X<int> a(mut);
   //X<int> b(con);
   X<const int> c(mut);
   X<const int> d(con);

   mut.f(mut);
   //mut.f(con);
   con.f(mut);
   con.f(con);

   //X<double> doub;
   //doub.f(mut);
}

One possibility is using member function templates, enabling them so as to achieve the combinations you want.

#include <utility>

template <class T, class U>
struct const_convertible;

template <class T>
struct const_convertible<T, T>: std::true_type {};

template <class T>
struct const_convertible<T, const T>: std::true_type {};

template <class T>
struct const_convertible<const T, T>: std::false_type {};

template <class T>
class X
{
public:
   X() {}
   X(const X&) {} //copy constructor
   //conversion constructor as needed
   template <class U>
   X(const X<U>&, typename std::enable_if<const_convertible<U, T>::value, void>::type* = 0)
   {}

   template <class U>
   typename std::enable_if<const_convertible<U, T>::value, void>::type f(X<U>) {}
};

int main()
{
   X<int> mut;
   X<const int> con;

   X<int> a(mut);
   //X<int> b(con);
   X<const int> c(mut);
   X<const int> d(con);

   mut.f(mut);
   //mut.f(con);
   con.f(mut);
   con.f(con);

   //X<double> doub;
   //doub.f(mut);
}
三生池水覆流年 2024-12-23 21:42:07

实现此目的的一种方法是通过部分模板专业化。您应该像平常一样为非 const 类型定义类:

template <typename T>
struct MyClass {
    void f(T&);
};

然后定义一个专门化

template <typename T>
struct MyClass<T const> {
    void f(T&);
    void f(T const&);
};

不幸的是,这会导致代码重复,但它应该允许您做您想做的事情。当然,您也可以让函数采用 MyClass&MyClass&

One way to do this is via partial template specialisation. You should define the class for non-const types as you usually would:

template <typename T>
struct MyClass {
    void f(T&);
};

Then define a specialisation

template <typename T>
struct MyClass<T const> {
    void f(T&);
    void f(T const&);
};

Unfortunately, this leads to code duplication, but it should allow you to do what you want. Naturally, you can have the functions take MyClass<T>& and MyClass<T const>&, too.

我不咬妳我踢妳 2024-12-23 21:42:07

我有点理解这个问题了。您可能可以使用模板专业化。

template <typename T>
class container
{
public:
   template<typename U>
   void addAll(const container<U>& b ){}
private:
   template<>
   void addAll(const container<int>&b); //No implementation
};

container<int> b;
....
container<const int> a;
a.addAll(b) ; //Give a link error, I can't understand why vc2010 compile and run this line though

I'm kind of understand the question a bit. You probably can use template specialization.

template <typename T>
class container
{
public:
   template<typename U>
   void addAll(const container<U>& b ){}
private:
   template<>
   void addAll(const container<int>&b); //No implementation
};

container<int> b;
....
container<const int> a;
a.addAll(b) ; //Give a link error, I can't understand why vc2010 compile and run this line though
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文