假设我有一个代码:
template <typename T>
class C {
public:
T f() { return m_result; }
void todo() { m_result = doit<T>(); }
private:
T m_result;
};
如果T
为void
,我想返回void
并且根本没有m_result
。
但是,编译器不允许实例化void
类型
其中一个决定是创建专业化。
template <> class C<void> { /* ... */ }
但我不知道如何支持几乎完全相同的代码
我怎样才能实例化m_result
?
我可以使用C ++ 17。谢谢!
答案 0 :(得分:4)
您可以将数据放在基类中,然后使用if constexpr
:
template<class T>
struct C_data{
T m_result;
};
template<>
struct C_data<void>{
};
template<class T>
class C: C_data<T>
{
static constexpr auto is_void = std::is_same_v<T,void>;
public:
auto f(){
if constexpr(is_void)
return this->m_result;
else
return;
}
void todo(){
if constexpr(is_void)
this->m_result = doit<T>();
else
doit<T>();
}
};
但是可以说C类的特化是更清晰的,因为模板类的所有成员都应该依赖于所有的模板参数(否则你应该拆分你的类以避免代码膨胀)。
所以我更喜欢完全专门化C,并使C语言的一部分独立于T,C的基类:
class C_base{
//any thing that is independent of T;
};
template<class T>
class C: public C_base{
//any thing that depend on T
};
template<>
class C<void>: public C_base{
//any thing that depend on T;
};
您还可以通过成员函数专门化成员功能,但我觉得它不太干净。
您将在标准库实现的几乎所有标题中找到最后一个代码结构。
答案 1 :(得分:2)
这对我有用:
#include <type_traits>
template <typename T> T doit() { return T{}; }
template <typename T> struct result_policy { T m_result; };
template <> struct result_policy<void> { };
template <typename T>
class C : private result_policy<T> {
public:
T f(){
if constexpr (!std::is_void_v<T>)
return result_policy<T>::m_result;
}
void todo() {
if constexpr(!std::is_void_v<T>)
result_policy<T>::m_result = doit<T>();
}
};
int main() {
C<int> ci;
ci.todo();
int i = ci.f();
C<void> cv;
cv.todo();
cv.f();
}
由于部分模板特化,我使用C ++ 17中的if constexpr
与m_result
一起使用并将m_result
存储到策略结构中仅用于非void类型。
答案 2 :(得分:0)
如果您可以使用C ++ 17,请尝试使用if constexpr
,std::is_same_v<>
和std::conditional_t<>
:
#include <type_traits>
// auxiliary variable template for checking against void type in a more readable way
template<typename T>
constexpr bool is_void_v = std::is_same_v<T, void>;
// auxiliary alias template for determining the type of the data member
// in order to prevent the compiler from creating member of type "void"
// so if T = void --> data member type as "int"
template<typename T>
using member_type_t = std::conditional_t<!is_void_v<T>, T, int>;
template <typename T>
class C{
public:
T f(){ return (T)m_result; } // no problem if T = void
void todo() {
if constexpr(!is_void_v<T>)
m_result = doit<T>();
else
doit<T>();
}
private:
member_type_t<T> m_result;
};
实际上,从C ++ 17开始,已经有一个std::is_void_v<>
变量模板type_traits
。