【发布时间】:2018-11-23 06:47:08
【问题描述】:
如果函数体没有意义(即无法编译),我经常使用 SFINAE 从重载集中删除函数。是否可以在 C++ 中添加一个简单的 require 语句?
例如,让我们有一个函数:
template <typename T>
T twice(T t) {
return 2 * t;
}
然后我得到:
twice(1.0);
twice("hello"); // Error: invalid operands of types ‘int’ and ‘const char*’ to binary ‘operator*’
我想得到一个错误,指出 twice 类型的参数没有函数 const char *
我很想写这样的东西:
template <typename T>
requires function_body_compiles
T twice(T t) {
return 2 * t;
}
然后我会得到
twice(1.0);
twice("hello"); // Error: no matching function for call to ‘twice2(const char [6])’
更多动力:我正在观看The Nightmare of Move Semantics for Trivial Classes 的演讲,他的最终 SFINAE 基本上是在说:在编译时使用这个构造函数。对于更复杂的构造函数,编写正确的 SFINAE 将是一场噩梦。
你认为在 c++ 中添加requires function_body_compiles 有意义吗?还是我缺少一个基本问题?这会被滥用或误用有多严重?
【问题讨论】:
-
这会使 SFINAE 对
T的要求不清楚。必须检查整个构造函数体以确定特定的T是否适合。 -
无法前向声明这样的模板。它会允许拼写错误或其他简单的拼写错误未被发现:假设函数体调用
printf,但你忘记了#include <stdio.h>。突然,整个过载消失了!这会是什么:template<typename T> requires function_body_compiles T once(T t) { return rand() ? once(t) : t; }?当且仅当函数体编译时,函数体才会编译。 -
@RaymondChen 前向声明绝对是一个非常有效的观点,是的,循环依赖肯定是一个问题,但即使现在你也可以实现这一点。实际上,Nicolai 在 38:50 左右的 CppCon 谈话中谈到了它。虽然,我看到你的错别字,但我认为它很容易被检测到。您尝试调用一个函数,编译器会告诉您没有这样的函数,因为您实际要调用的函数由于拼写错误而被删除。唯一的问题是如果有另一个函数重载匹配,它是否经常发生?
-
这不就是概念的全部内容吗? (而不是合同)
-
@Francis Cugler 只需要一个谓词的否定,例如
require !std::is_same_v<T, int>。当然,你可以引入一个谓词或一个概念更好的名称,但绝对不需要新的关键字。
标签: c++ templates c++20 definition-checking