为神秘的标题道歉。假设这个定义:
struct TestNode {
using CostType = double;
};
我希望能够像这样定义一个类模板:
template <typename NodeP,
typename MyPolicy = /* CostType of the node type corresponding to NodeP */ >
struct TT {
};
在上面的定义中,NodeP
可以是定义CostType
的类的简单或智能指针,例如TestNode
。问题:如何将MyPolicy
模板参数的默认值指定为与CostType
对应的节点类型的NodeP
?
到目前为止,这是我的解决方案:
// like std::remove_pointer, but works with smart pointers as well
template <typename PT> struct my_remove_pointer {
using type = typename
std::remove_reference< decltype( *((PT)nullptr) ) >::type;
};
struct TestNode {
using CostType = double;
};
template <typename NodeP,
typename MyPolicy = typename my_remove_pointer<NodeP>::type::CostType>
struct TT {
};
这个问题是否有更简单的方法?特别是,我错过了一个标准的库设施,可以使解决方案更简单吗?
答案 0 :(得分:7)
标准库中有一个名为pointer_traits
的辅助类。看起来它正是你想要的。
#include <iostream>
#include <memory>
#include <typeinfo>
struct TestNode {
using CostType = double;
};
template <typename NodeP,
typename MyPolicy = typename std::pointer_traits<NodeP>::element_type::CostType>
struct TT {
typedef MyPolicy xxx;
};
int main () {
TT<TestNode*>::xxx a = 2.8;
TT<std::unique_ptr<TestNode>>::xxx b = 3.14;
std::cout << a << std::endl;
std::cout << b << std::endl;
return 0;
}
答案 1 :(得分:1)
通过一些使用,我可能会更具可读性
template<typename T>
using remove_pointer_t = typename my_remove_pointer<T>::type;
template<typename T>
using cost_type_t = typename remove_pointer_t<T>::CostType;
现在在你的代码中
template <typename NodeP,
typename MyPolicy = cost_type_t<NodeP>>
struct TT {
};
答案 2 :(得分:0)
由于智能指针支持解除引用和.get()
,我们可以使用void_t
编写一个类型特征来获取基础类型:
template <typename... >
using void_t = void;
// base case: not any kind of pointer
template <typename T, typename = void>
struct underlying_type {
using type = T;
};
// raw pointer
template <typename T, typename = void>
struct underlying_type<T*, void> {
using type = T;
};
// smart pointer
template <typename T>
struct underlying_type<T, void_t<
decltype(*std::declval<T>()),
decltype(std::declval<T>().get())
>>
{
using type = std::remove_reference_t<
decltype(*std::declval<T>())
>;
};
template <typename T>
using underlying_type_t = typename underlying_type<T>::type;
如果不需要支持非指针(我不确定),那么你可以这样做:
template <typename T>
using underlying_type_t = std::remove_reference_t<decltype(*std::declval<T>())>;
无论哪种方式,一旦你有了别名:
template <typename NodeP,
typename MyPolicy = underlying_type_t<NodeP>::Cost>
struct TT { ... };