c++ 指针类型和常规类型的类模板

mnemlml8  于 11个月前  发布在  其他
关注(0)|答案(3)|浏览(89)

我定义了一个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 *>来选择合适的定义,但问题是,这两个定义将共享许多代码。

vtwuwzda

vtwuwzda1#

标签:C++ template specialization, calling methods on types that could be pointers or references unambiguously
同样的技术在这里也可以工作,允许您在两种情况下统一地将val作为引用(或指针)处理。
CRTP可以帮助减少代码重复,允许两个专门化的公共代码而没有任何开销。
请注意,当您有时使用指针,有时使用示例时,所有权语义会变得棘手--如果val有时是参数的指针,而其他时候是参数的副本,那么val的生存期是多少?如何强制执行它?

ezykj2lf

ezykj2lf2#

还有一种方法可以做到这一点。你应该使用类型traits,它们在编译时被评估。这就是你如何修改。

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;
    }
}

字符串

7xllpg7q

7xllpg7q3#

遇到类似的问题,我是这样解决的:

#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

相关问题