Herb Sutter 回归基础!CppCon 上的现代C++演示要点讨论了传递参数的不同选项,并将其性能与写作/教学的简易性进行了比较."高级"选项(在所有测试的案例中提供最佳性能,但对大多数开发人员来说难以编写)是完美转发,给出了示例(PDF,第28页):
class employee {
std::string name_;
public:
template <class String,
class = std::enable_if_t<!std::is_same<std::decay_t<String>,
std::string>::value>>
void set_name(String &&name) noexcept(
std::is_nothrow_assignable<std::string &, String>::value) {
name_ = std::forward<String>(name);
}
};
Run Code Online (Sandbox Code Playgroud)
该示例使用带转发引用的模板函数,模板参数String使用约束enable_if.然而,约束似乎是不正确的:似乎只有在String类型不是a 时才使用此方法std::string,这没有任何意义.这将意味着该std::string成员可以使用设置什么,但一个std::string值.
using namespace std::string_literals;
employee e;
e.set_name("Bob"s); // error
Run Code Online (Sandbox Code Playgroud)
我考虑的一个解释是,有一个简单的拼写错误,而且约束的目的是std::is_same<std::decay_t<String>, std::string>::value代替!std::is_same<std::decay_t<String>, std::string>::value.然而,这意味着setter不能使用,例如,const char *它显然是打算使用这种类型,因为这是在演示文稿中测试的案例之一.
在我看来,正确的约束更像是:
template <class String,
class = std::enable_if_t<std::is_assignable<decltype((name_)),
String>::value>>
void set_name(String &&name) …Run Code Online (Sandbox Code Playgroud) (有些)过时的文章探讨了decltype与SFINAE一起使用的方法,以检测某种类型是否支持某些运算符,例如==或<.
以下是检测类是否支持<运算符的示例代码:
template <class T>
struct supports_less_than
{
static auto less_than_test(const T* t) -> decltype(*t < *t, char(0))
{ }
static std::array<char, 2> less_than_test(...) { }
static const bool value = (sizeof(less_than_test((T*)0)) == 1);
};
int main()
{
std::cout << std::boolalpha << supports_less_than<std::string>::value << endl;
}
Run Code Online (Sandbox Code Playgroud)
这输出true,因为当然std::string支持<操作员.但是,如果我尝试将它与不支持<运算符的类一起使用,我会收到编译器错误:
error: no match for ‘operator<’ in ‘* t < * t’
Run Code Online (Sandbox Code Playgroud)
所以SFINAE不在这里工作.我在GCC 4.4和GCC …
通过使用Expression SFINAE,您可以检测是否支持某些操作员或操作.
例如,
template <class T>
auto f(T& t, size_t n) -> decltype(t.reserve(n), void())
{ t.reserve(n); }
Run Code Online (Sandbox Code Playgroud)
我的问题是t.reserve(n)内部decltype被执行与否?
如果是,这是否意味着t.reserve(n)执行了两次,一次在内部decltype,另一次在函数体内?
如果没有,是否只是在编译期间检查验证?但是为什么它没有被执行,我认为逗号分隔表达式列表中的所有表达式都将被执行.