我正在尝试了解SFINAE
(我正在关注本教程),但有一些......“设计选择”我不理解,因此,我发现它们令人困惑。
假设我遇到这样的情况(包括重新实现std::enable_if
is there 只是为了演示我是如何理解的enable_if
)
// A default class (class type) declaration. Nothing unusual.
template <bool, typename T = void>
struct enable_if
{};
// A specialisation for <true, T> case. I understand 'why-s' of this.
// -- 'why-s': if I attempt to access 'enable_if<false, T>::type' (which does not exist) I will get a substitution failure and compiler will just "move-on" trying to match "other cases".
template <typename T>
struct enable_if<true, T> {
typedef T type;
};
// Here lies my problem:
template <class T,
typename std::enable_if<std::is_integral<T>::value,T>::type* = nullptr>
void do_stuff(T& t) { /* do stuff */ };
Run Code Online (Sandbox Code Playgroud)
(1)我遇到的第一个问题是bool
字面意思 ( true
/ false
)。我知道它们是正确的,模板可以接受原始数据类型(普通旧数据类型)的编译时常量值,但如果我的任务是设计“机制enable_if
”而不是使用true
/false
我会创建一个标记类true_t
(或True
)和false_t
(或False
)如下:
class true_t {}; // or True
class false_t {}; // or False
template<typename T>
class is_integral // just to have "something" to use with "enable_if"
{
using result = false_t;
};
template<>
class is_integral<int32_t> // same with all other int types
{
using result = true_t;
};
template <typename B, typename T = void>
struct enable_if
{};
template <typename T>
struct enable_if<true_t, T>
{
using type = T;
};
Run Code Online (Sandbox Code Playgroud)
(2)我发现多余的第二件事是需要指定typename T
模板参数。enable_if
按如下方式实现不是更容易/更好吗:
template <typename B>
struct enable_if
{};
template <>
struct enable_if<true_t>
{
using type = void; // the 'type' exists therefore substitution failure will not occur.
};
Run Code Online (Sandbox Code Playgroud)
我很清楚我的所有主张都远远不如当前现有的解决方案SFINAE
,但我不明白为什么......我削减了当前功能(重要功能)的哪一部分?(连自己都没有意识到……)
我知道,在这个网站上,我有义务以......单个“问题帖子式”格式提出一个问题,但如果您认为可以接受,我也可以问一下这个语法是什么:
std::enable_if</* ... */>::type* = nullptr
Run Code Online (Sandbox Code Playgroud)
完成?现在超出了我的理解范围...
我遇到的第一件事就是
bool
字面意思(true
/false
)。我知道它们是正确的,模板可以接受原始数据类型(普通旧数据类型)的编译时常量值,但如果我的任务是设计“机制enable_if
”而不是使用true
/false
我会创建一个标记类true_t
(或True
)和false_t
(或False
)如下
使用标记类型而不仅仅是 bool 的问题是您必须为代码添加额外的复杂性。如果您想检查编译时条件,例如sizeof
,您不能只执行sizeof(T) == 8
. 您必须进行抽象来执行检查并返回适当的标记类型。
我发现多余的第二件事是需要指定
typename T
模板参数。enable_if
按如下方式实施不是更容易/更好吗
并不真地。如果您想使用 SFINAE 作为返回类型怎么办?那么你只能有一个 void 函数,这是不必要的限制。相反,您可以使用后来在 C++14 和 C++17 中添加的内容并创建别名。这使得名称不相关,并允许您删除typename
template< bool B, class T = void >
using enable_if_t = typename enable_if<B,T>::type;
template< class T >
inline constexpr bool is_integral_v = is_integral<T>::value;
Run Code Online (Sandbox Code Playgroud)
这允许您重写
template <class T,
typename std::enable_if<std::is_integral<T>::value,T>::type* = nullptr>
void do_stuff(T& t) { /* do stuff */ };
Run Code Online (Sandbox Code Playgroud)
到
template <class T,
std::enable_if_t<std::is_integral_v<T>,T>* = nullptr>
void do_stuff(T& t) { /* do stuff */ };
Run Code Online (Sandbox Code Playgroud)
虽然我更喜欢使用 bool 来表示enable_if_t
类似的类型
template <class T,
std::enable_if_t<std::is_integral_v<T>, bool> = true>
void do_stuff(T& t) { /* do stuff */ };
Run Code Online (Sandbox Code Playgroud)
我知道,在这个网站上,我有义务以......单个“问题帖子式”格式提出一个问题,但如果您认为可以接受,我也可以问一下这个语法是什么:
Run Code Online (Sandbox Code Playgroud)std::enable_if</* ... */>::type* = nullptr
完成?
它创建一个指向“返回”类型的指针std::enable_if
并将其设置为空指针。这里的目标是创建一个仅在条件为真时才存在的模板参数。你可以将其重写为
typename = typename std::enable_if</* ... */>::type
Run Code Online (Sandbox Code Playgroud)
因此,您拥有类型参数,而不是非类型参数。它们都完成相同的事情,但后者无法重载不同的函数,enable_if
因为默认模板参数不是签名的一部分。使用非类型参数的第一个版本包含在函数签名中,并且允许您重载enable_if
's。
归档时间: |
|
查看次数: |
1375 次 |
最近记录: |