在读<<C++ Templates>>第二版时,有一个模板问题,代码如下:
模板定义:
#include <utility>
template <typename F, typename... Args, typename = decltype(std::declval<F>()(std::declval<Args &&>()...))>
std::true_type isValidImpl(void *);
template <typename F, typename... Args>
std::false_type isValidImpl(...);
inline constexpr auto isValid = [](auto f) {
return [](auto &&... args) {
return decltype(isValidImpl<decltype(f), decltype(args) &&...>(nullptr)){};
};
};
template <typename T>
struct TypeT
{
using Type = T;
};
template <typename T>
constexpr auto type = TypeT<T>{};
template <typename T>
T valueT(TypeT<T>);
constexpr auto isDefaultConstructible = isValid([](auto x) -> decltype((void)decltype(valueT(x))()) {});
如果一个 lambda 函数不执行是不是就不检查返回类型合法性了呢,比如在执行isDefaultConstructible(type<x>)
命令时,会引入一个 lamda 函数,这个 lambda 函数返回值是decltype((void)decltype(valueT(x))()) {})
, decltype(valueT(x))()
在 x 是 int 的时候合法,导致最终调用第一个isValidImpl
函数,x 是 int&的时候不合法,把第一个isValidImpl
SFINAE out,调用第二个此优先级isValidImpl
函数,即使 isValid 传入的是一个不合法 lambda 函数,但是由于没有使用所以没有检查 lambda 函数合法性,我的理解正确吗?
1
GeruzoniAnsasu 2020-06-19 12:50:23 +08:00
这。。 写的啥东西
强烈建议你自己丢到 clion 里去调一调这是在干什么 首先莫名其妙的 inline 是哪来的? 然后最后这个 isDefaultConstructible 是啥意思? 它是一个 is_valid 返回的 lambda,接受任意多个参数 我觉得这坨面条可能跟你预期的完全不一样 |
2
Tony042 OP @GeruzoniAnsasu 这个是可以跑通的,只不过用了 lambda 闭包,需要 C++17 及以上标准,已经在 GCC10 和 MSVC 16.9 都测试过了,没问题的,isDefaultConstructible 是一个 lamda 函数,用来返回类型是否有默认构造函数,如果有默认构造函数则返回 std::true_type 否则返回 std::false_type, 用法是 isConstructible(type<int>),当然你也可以再定义一个类型模板 template <typename T>
using isDefaultConstructibleT = decltype(isDefaultConstructible(type<T>)); |
3
Tony042 OP @GeruzoniAnsasu 然后这个是 C++ templates 2nd edition 19.4.3 的一个例子,我有个地方不太理解,就发上来一下,至于 inline 我推测作者放在这的位置是为了优化性能,不过 inline 这个还是要看编译器,应该没影响的,这个模板函数看起来确实比较唬人,不过仔细看应该还是可以理解的
|
4
Tony042 OP @GeruzoniAnsasu 不好意思,我没有把条件说清澈,是我的锅
|
5
GeruzoniAnsasu 2020-06-19 13:48:49 +08:00
行 8 那用法解决之后
实际上逻辑就是检查 typename = decltype(std::declval<F>()(std::declval<Args &&>()...)) 合不合法,进一步来说,就只是检查 declval<传进去的那个参数&&>() 合不合法 这不就跟 stl 的实现一样的 |
6
hankai17 2020-06-19 14:04:12 +08:00
头晕 好复杂
|
7
wutiantong 2020-06-22 10:34:17 +08:00
--- 如果一个 lambda 函数不执行是不是就不检查返回类型合法性了呢?
你的这个问题没提对,因为代码中相关处所涉及的并非普通的 lambda 而是 generic lambda,就你的这个问题这两者是完全不同的。 |
8
Tony042 OP @wutiantong 不好意思,我这个提问题提的确实有不妥,那这个 generic lambda 是不是由于不实例化就不检查返回类型合法性了呢
|
9
wutiantong 2020-06-23 13:25:03 +08:00
@Tony042 是啊,generic lambda 的 operator() 是个模板成员函数,所以在实例化之前什么都不会发生。
|
10
Wirbelwind 2020-06-23 15:06:28 +08:00
不是因为你的 lambda 不合法,如果不合法,编译过不去。
注意 std::false_type 那个函数,parameter 是...,匹配任何参数,所以才可以匹配到这个函数。 当匹配不到 std::true_type 时候,其他情况都匹配 std::false_type,declval 是不求值才用的。 当 lambda 也不匹配的时候,也都匹配 std::false_type |
11
Wirbelwind 2020-06-23 15:09:31 +08:00
请问楼主看的具体(全名)是哪本书,求推荐
|
12
Tony042 OP @Wirbelwind 返回值是有可能不合法的,decltype((void)decltype(valueT(x))()) ,当 x 是 type(int&)的时候就不合法,书名就叫<<C++ Templates>> 2nd edition
|
13
Wirbelwind 2020-06-24 09:42:22 +08:00
@Tony042 你说的不合法只是进了那个 std::false_type 的函数,这是你自己定义的
|
14
Wirbelwind 2020-06-24 09:43:24 +08:00
@Wirbelwind 推断使用了那个函数 表达式本身不求值
|
15
BasIrs 2020-07-28 16:27:13 +08:00
我们可以这样定义一个 Lambda 函数:
#include <iostream> int main(){ auto f1 = [] () { std::cout << "I am Lambda"; };//省略函数类型 auto f2 = [] () -> int { std::cout << "I am Lambda too"; return 1; };//函数类型后置 } -----来自百度 |