同时具有指针类型和常规类型的类模板

问题描述 投票:0回答:3

我定义了一个 Node 类,其值类型带有模板

template<class T>
class Node {
  T val;
  public:
    Node (T & v) : val (v) {}
    ...
    void print() { cout << v << endl; }
}

大多数时候,感兴趣的节点值将是一个对象类,例如

class Foo
。在这种情况下,使用
Node<Foo *>
会更方便。但也有可能该节点将保留原始时间,比如
int
。然后使用
Node<int>
就足够了。

问题是,某些函数可能需要根据

T
是否为指针类型而有不同的行为。例如,如果是
print
,则应为
cout << *v
,否则应为
cout << v

我尝试过定义两者:

template<class T>
class Node {
  T val;
  public:
    Node (T & v) : val (v) {}
    ...
    void print() { cout << v << endl; }
}

template<class T>
class Node<T*> {
  T* val;
  public:
    Node (T* v) : val (v) {}
    ...
    void print() { cout << *v << endl; }
}

现在可以根据是否是

Node<int> or Node<int *>
选择合适的定义,但问题是,这两个定义将共享许多代码。我想知道是否有更好的方法来实现这一目标。

c++ templates pointers
3个回答
4
投票

请参阅:C++ 模板专门化,明确调用可能是指针或引用的类型上的方法

这里应该使用相同的技术,允许您在两种情况下统一将

val
处理为引用(或指针)。

CRTP 可能有助于减少代码重复,也允许两个专业化使用通用代码,而无需任何开销。

请注意,当您有时使用指针,有时使用实例时,所有权语义会变得棘手 - 如果有时它是参数的指针,有时它是参数的副本,那么

val
的生命周期是多少,以及如何你强制执行吗?


2
投票

嗯,还有另一种方法可以做到这一点。您应该使用类型特征,它们在编译时进行评估。您可以这样修改。

template<class T>
class Node {
  T val;
  public:
    Node (T & v) : val (v) {}
    ...
    void print() { 
      if(std::is_pointer<T>::value)
        cout << *v << endl;
      else
        cout << v << endl;
    }
}

0
投票

有类似的问题,这就是我解决的方法:

#include <iostream>
#include <memory>

template<typename T> struct is_shared_ptr : std::false_type {};
template<typename T> struct is_shared_ptr<std::shared_ptr<T>> : std::true_type {};

template<typename T>
void is_shared(const T& t) {
    std::cout << is_shared_ptr<T>::value << std::endl;
}

template<typename T>
T* to_ptr(T& obj) {
    std::cout << "Ref to Ptr" << std::endl;
    return &obj;
}

template<typename T>
T* to_ptr(std::shared_ptr<T> & obj) {
    std::cout << "SharedPtr to Ptr" << std::endl;
    return obj.get();
}

template<typename T>
T* to_ptr(T* obj) {
    std::cout << "Ptr to Ptr" << std::endl;
    return obj;
}

// This is my usecase: Depending on the type, `.` or `->` is needed.
// But the if T = shared_ptr<Text>, `->` did not work...
template<typename T>
void free_printsize(T t){
    auto t_ptr = to_ptr(t);
    t_ptr->printsize();
}

class Text{
    std::string text_;
public:
    Text(const std::string &t){ text_ = t; }
    void printsize() const{
        std::cout << "Size of '" << text_ << "': " << text_.size();
    }
};

int main()
{    
    std::cout << "Testing value object: ";
    Text test("Hello");    
    is_shared(test);
    free_printsize(test);

    std::cout << "\n\nTesting ptr: ";
    Text* test_ptr = &test;
    is_shared(test_ptr);
    free_printsize(test_ptr);

    std::cout << "\n\nTesting shared ptr: ";
    std::shared_ptr<Text> test_sp = std::make_shared<Text>("Hello");
    is_shared(test_sp);
    free_printsize(test_sp);

    return 0;
}

输出:

Testing value object: 0
Ref to Ptr
Size of 'Hello': 5
Testing ptr: 0
Ptr to Ptr
Size of 'Hello': 5
Testing shared ptr: 1
SharedPtr to Ptr
Size of 'Hello': 5
Process exited with code: 0
© www.soinside.com 2019 - 2024. All rights reserved.