我定义了一个 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++ 模板专门化,明确调用可能是指针或引用的类型上的方法
这里应该使用相同的技术,允许您在两种情况下统一将
val
处理为引用(或指针)。
CRTP 可能有助于减少代码重复,也允许两个专业化使用通用代码,而无需任何开销。
请注意,当您有时使用指针,有时使用实例时,所有权语义会变得棘手 - 如果有时它是参数的指针,有时它是参数的副本,那么
val
的生命周期是多少,以及如何你强制执行吗?
嗯,还有另一种方法可以做到这一点。您应该使用类型特征,它们在编译时进行评估。您可以这样修改。
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;
}
}
有类似的问题,这就是我解决的方法:
#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