sky*_*ack 16 c++ templates decltype sfinae c++17
考虑以下基于以下的基本示例void_t:
template<typename, typename = void_t<>>
struct S: std::false_type {};
template<typename T>
struct S<T, void_t<decltype(std::declval<T>().foo())>>: std::true_type {};
Run Code Online (Sandbox Code Playgroud)
它可以如下使用:
template<typename T>
std::enable_if_t<S<T>::value> func() { }
Run Code Online (Sandbox Code Playgroud)
使用尾随返回类型可以完成相同的操作decltype:
template<typename T>
auto func() -> decltype(std::declval<T>().foo(), void()) { }
Run Code Online (Sandbox Code Playgroud)
对于我想到的所有例子都是如此.我找不到一个案例,其中任何一个void_t或尾随返回类型decltype可以使用,而其对应的不能.
最复杂的情况可以通过尾随返回类型和重载的组合来解决(例如,当检测器用于在两个函数之间切换而不是作为禁用或启用某些东西的触发器时).
是这样的吗?他们是(void_t和decltype作为后返回类型以及如果需要重载)完全互换?
否则,是什么情况下,一个人不能用来解决约束,我被迫使用一个特定的方法?
这是元编程的等价物:我应该编写一个函数,还是应该只编写内联代码.更喜欢编写类型特征的原因与更喜欢编写函数的原因相同:它更自我记录,可重用,更容易调试.更喜欢编写尾随decltype的原因类似于更喜欢编写内联代码的原因:它是一次性的,不能重复使用,所以为什么要把它分解出来并为它提出一个合理的名称?
但是,为什么你可能想要一个类型特征,这里有很多原因:
假设我有一个特点,我想多次检查.喜欢fooable.如果我写一次类型特征,我可以将其视为一个概念:
template <class, class = void>
struct fooable : std::false_type {};
template <class T>
struct fooable<T, void_t<decltype(std::declval<T>().foo())>>
: std::true_type {};
Run Code Online (Sandbox Code Playgroud)
现在我可以在很多地方使用相同的概念:
template <class T, std::enable_if_t<fooable<T>{}>* = nullptr>
void bar(T ) { ... }
template <class T, std::enable_if_t<fooable<T>{}>* = nullptr>
void quux(T ) { ... }
Run Code Online (Sandbox Code Playgroud)
对于检查多个表达式的概念,您不希望每次都重复它.
伴随着重复,组成两种不同类型的特征很容易:
template <class T>
using fooable_and_barable = std::conjunction<fooable<T>, barable<T>>;
Run Code Online (Sandbox Code Playgroud)
编写两个尾随返回类型需要写出所有两个表达式...
使用类型特征,很容易检查类型是否不满足特征.那只是!fooable<T>::value.你不能写一个trailing decltype表达式来检查某些东西是无效的.当您有两个不相交的重载时,可能会出现这种情况:
template <class T, std::enable_if_t<fooable<T>::value>* = nullptr>
void bar(T ) { ... }
template <class T, std::enable_if_t<!fooable<T>::value>* = nullptr>
void bar(T ) { ... }
Run Code Online (Sandbox Code Playgroud)
这很好地导致......
假设我们有一个短类型特征,用类型特征标记调度更加清晰:
template <class T> void bar(T , std::true_type fooable) { ... }
template <class T> void bar(T , std::false_type not_fooable) { ... }
template <class T> void bar(T v) { bar(v, fooable<T>{}); }
Run Code Online (Sandbox Code Playgroud)
比起其他情况:
template <class T> auto bar(T v, int ) -> decltype(v.foo(), void()) { ... }
template <class T> void bar(T v, ... ) { ... }
template <class T> void bar(T v) { bar(v, 0); }
Run Code Online (Sandbox Code Playgroud)
该0和int/...是一点都不奇怪,不是吗?
static_assert如果我不想在一个概念上使用SFINAE,而只是想用一个明确的消息来努力失败怎么办?
template <class T>
struct requires_fooability {
static_assert(fooable<T>{}, "T must be fooable!");
};
Run Code Online (Sandbox Code Playgroud)
当(如果?)我们得到概念时,显然实际上使用概念在涉及元编程的所有事情上都要强大得多:
template <fooable T> void bar(T ) { ... }
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
378 次 |
| 最近记录: |