处理条件编译的多个条件的最佳方法
Best way to handle multiple conditions for conditional compilation
我有一个模板 class,它有一个方法,其中模板参数指定该方法的输入和输出,如下所示:
template <typename In, typename Out>
class Foo
{
Out fn(const In& in)
{
Out out;
return out;
}
}
所以我尝试了这个,但是当尝试将 void
用于 In
或 Out
时(可能很明显)出现错误。所以我尝试添加多种方法,这些方法是这个主题的变体,希望它们的替换能够启用相关功能并禁用无效功能:
template <std::enable_if_t<std::is_void<InputType>::value>* = nullptr>
OutputType fn()
{
OutputType out;
return out;
}
template <std::enable_if<(!std::is_void<OutputType>::value) && (!std::is_void<InputType>::value)>* = nullptr>
OutputType fn(InputType& t)
{
OutputType out;
return out;
}
template <std::enable_if<std::is_void<OutputType>::value>* = nullptr>
void fn(InputType& t)
{}
这让我回到了 "invalid reference to void" 领域,或者签名冲突。
我应该如何优雅地处理这些情况,以便仅从模板创建以下签名之一:
/*In == void && Out != void*/
Out fn(/* no input here to keep compiler happy*/) { return Out; }
/*In != void && Out != void, standard case*/
Out fn(const In& in) { return Out; }
/*In != void && Out == void*/
void fn(const In& in) { /* No returns here to keep compiler happy*/; }
当两者都无效时,您可以使用 partial specialisation to provide implementations of Foo
for when either of In
and Out
are void, and explicit specialisation。
语法如下(注意 Foo
后的尖括号表示这是主要 Foo
class 模板的 specialisation )
template<typename Out>
struct Foo<void, Out> // specialisation for only In = void
{ ... };
template<typename In>
struct Foo<In, void> // specialisation for only Out = void
{ ... };
template<>
struct Foo<void, void> // specialisation for both In and Out = void
{ ... };
这是一个例子:
#include <iostream>
// primary class template
template <typename In, typename Out>
struct Foo {
Out fn(const In& in) { return Out{}; }
};
// partial specialisation for when In=void
template<typename Out>
struct Foo<void, Out> {
Out fn() { return Out{}; }
};
// partial specialisation for when Out=void
template<typename In>
struct Foo<In, void> {
void fn(const In& in) { }
};
// explicit specialisation for when both In=void and Out=void
template<>
struct Foo<void, void> {
void fn() { }
};
int main() {
Foo<int, double> f;
f.fn(5);
Foo<void, void> g;
g.fn();
Foo<void, int> h;
h.fn();
Foo<int, void> i;
i.fn(5);
return 0;
}
return值和输入值是不同的问题,你可以独立解决。
首先,我建议您调换模板类型的顺序:首先Out
,其次In
。
这是因为如果您在可变输入类型列表中转换 In
template <typename Out, typename ... Ins>
struct Foo { /* ... */ };
你自动解决void
输入类型(你根本不表达)
这不是一个很好的解决方案,因为可能很难使用输入值;只是为了向您展示如何创建适用于所有情况的 struct/method。
对于return void
类型,你可以简单地做
return (Out)someVal;
其中 someVal
是 Out
类型,当 Out
不是 void
时,另一种类型(例如:int
)如果Out
是 void
.
所以如果你定义一个类型特征deVoid
如下
template <typename T>
struct deVoid
{ using type = T; };
template <>
struct deVoid<void>
{ using type = int; }; // a fake not-void type
template <typename T>
using deVoid_t = typename deVoid<T>::type;
你可以定义out
变量如下
deVoid_t<Out> out {};
和return
这样
return (Out)out;
当 Out
为 void
时也有效。
所以可以这样写Foo
template <typename Out, typename ... Ins>
struct Foo
{
Out fn (Ins const & ... ins)
{
deVoid_t<Out> out {};
return (Out)out;
}
};
适用于零输入类型(例如 void
输入类型)和 void
return 类型。
以下是一个完整的工作示例
template <typename T>
struct deVoid
{ using type = T; };
template <>
struct deVoid<void>
{ using type = int; }; // a fake not-void type
template <typename T>
using deVoid_t = typename deVoid<T>::type;
template <typename Out, typename ... Ins>
struct Foo
{
Out fn (Ins const & ... ins)
{
deVoid_t<Out> out {};
return (Out)out;
}
};
int main ()
{
Foo<int, int> f; f.fn(42);
Foo<void> g; g.fn();
Foo<int> h; h.fn();
Foo<void, int> i; i.fn(42);
Foo<void, int, long> j; j.fn(42, 84L);
}
我有一个模板 class,它有一个方法,其中模板参数指定该方法的输入和输出,如下所示:
template <typename In, typename Out>
class Foo
{
Out fn(const In& in)
{
Out out;
return out;
}
}
所以我尝试了这个,但是当尝试将 void
用于 In
或 Out
时(可能很明显)出现错误。所以我尝试添加多种方法,这些方法是这个主题的变体,希望它们的替换能够启用相关功能并禁用无效功能:
template <std::enable_if_t<std::is_void<InputType>::value>* = nullptr>
OutputType fn()
{
OutputType out;
return out;
}
template <std::enable_if<(!std::is_void<OutputType>::value) && (!std::is_void<InputType>::value)>* = nullptr>
OutputType fn(InputType& t)
{
OutputType out;
return out;
}
template <std::enable_if<std::is_void<OutputType>::value>* = nullptr>
void fn(InputType& t)
{}
这让我回到了 "invalid reference to void" 领域,或者签名冲突。
我应该如何优雅地处理这些情况,以便仅从模板创建以下签名之一:
/*In == void && Out != void*/
Out fn(/* no input here to keep compiler happy*/) { return Out; }
/*In != void && Out != void, standard case*/
Out fn(const In& in) { return Out; }
/*In != void && Out == void*/
void fn(const In& in) { /* No returns here to keep compiler happy*/; }
当两者都无效时,您可以使用 partial specialisation to provide implementations of Foo
for when either of In
and Out
are void, and explicit specialisation。
语法如下(注意 Foo
后的尖括号表示这是主要 Foo
class 模板的 specialisation )
template<typename Out>
struct Foo<void, Out> // specialisation for only In = void
{ ... };
template<typename In>
struct Foo<In, void> // specialisation for only Out = void
{ ... };
template<>
struct Foo<void, void> // specialisation for both In and Out = void
{ ... };
这是一个例子:
#include <iostream>
// primary class template
template <typename In, typename Out>
struct Foo {
Out fn(const In& in) { return Out{}; }
};
// partial specialisation for when In=void
template<typename Out>
struct Foo<void, Out> {
Out fn() { return Out{}; }
};
// partial specialisation for when Out=void
template<typename In>
struct Foo<In, void> {
void fn(const In& in) { }
};
// explicit specialisation for when both In=void and Out=void
template<>
struct Foo<void, void> {
void fn() { }
};
int main() {
Foo<int, double> f;
f.fn(5);
Foo<void, void> g;
g.fn();
Foo<void, int> h;
h.fn();
Foo<int, void> i;
i.fn(5);
return 0;
}
return值和输入值是不同的问题,你可以独立解决。
首先,我建议您调换模板类型的顺序:首先Out
,其次In
。
这是因为如果您在可变输入类型列表中转换 In
template <typename Out, typename ... Ins>
struct Foo { /* ... */ };
你自动解决void
输入类型(你根本不表达)
这不是一个很好的解决方案,因为可能很难使用输入值;只是为了向您展示如何创建适用于所有情况的 struct/method。
对于return void
类型,你可以简单地做
return (Out)someVal;
其中 someVal
是 Out
类型,当 Out
不是 void
时,另一种类型(例如:int
)如果Out
是 void
.
所以如果你定义一个类型特征deVoid
如下
template <typename T>
struct deVoid
{ using type = T; };
template <>
struct deVoid<void>
{ using type = int; }; // a fake not-void type
template <typename T>
using deVoid_t = typename deVoid<T>::type;
你可以定义out
变量如下
deVoid_t<Out> out {};
和return
这样
return (Out)out;
当 Out
为 void
时也有效。
所以可以这样写Foo
template <typename Out, typename ... Ins>
struct Foo
{
Out fn (Ins const & ... ins)
{
deVoid_t<Out> out {};
return (Out)out;
}
};
适用于零输入类型(例如 void
输入类型)和 void
return 类型。
以下是一个完整的工作示例
template <typename T>
struct deVoid
{ using type = T; };
template <>
struct deVoid<void>
{ using type = int; }; // a fake not-void type
template <typename T>
using deVoid_t = typename deVoid<T>::type;
template <typename Out, typename ... Ins>
struct Foo
{
Out fn (Ins const & ... ins)
{
deVoid_t<Out> out {};
return (Out)out;
}
};
int main ()
{
Foo<int, int> f; f.fn(42);
Foo<void> g; g.fn();
Foo<int> h; h.fn();
Foo<void, int> i; i.fn(42);
Foo<void, int, long> j; j.fn(42, 84L);
}