
在读<<C++ Templates>>第二版时,有一个模板问题,代码如下:
模板定义:
#include <utility> template <typename F, typename... Args, typename = decltype(std::declvl<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; };//函数类型后置 } -----来自百度 |