cpp 日常


1,
template<typename Res, typename Obj> Res apply(Obj&& obj)
{
  return helper::template apply<Res, Obj>(type_index_, data_.raw(), obj);
}

上面代码中apply 函数返回data_中储存的对象,如果data_中没有储存有对象,那么返回空对象Res{}。 然而上面代码却有一个问题:如果Resvoid呢? 这时就变成了 return void{},这是不允许的,你不能构造一个void对象。

根据n4659的[expr.type.conv],有这样一段话

If the initializer is a parenthesized single expression, the type conversion expression is equivalent (in definedness,
and if defined in meaning) to the corresponding cast expression (8.4). If the type is cv void and the initializer
is (), the expression is a prvalue of the specified type that performs no initialization. Otherwise, the expression
is a prvalue of the specified type whose result object is direct-initialized (11.6) with the initializer. For an
expression of the form T(), T shall not be an array type.

可以看出,对于void()这个prvalue是不会初始化的,你还会发现

static_asssert(is_same_v<decltype(void()), void>);

不会出现编译错误。至于为什么会出现在[expr.type.conv],恐怕和旧式的类型转换有关

void foo() { int x; return (void)x; } // c-style
void bar() { int x; return void(x); } // old style
void baz() { int x; return static_cast<void>(x); } // type conversion expression

上面三个转换中,总是应该用static_cast。说道static_cast想到了一个问题:static_cast会分配内存空间吗? 答案是看情况,比如 string s = static_cast<string>("233")肯定会构造一个string啊。另外,static_cast可以用来玩Andrei Alexandrescu说的static polymorphism。

2,

一个新东西

template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;

第一行是惯用法CRTP不用解释,那么第二行是啥????既不是函数又不是结构体还和结构体重名了,到底是个啥???

这就是那个新东西。

C++17刚出来那会儿就了解过模板参数推断这个东西,很简单的认为就是不需要显式的写出模板参数,编译器会根据构造函数参数类型来推断,像这样

template<typename T> struct Foo { Foo(T) {} };
Foo foo(233); // T is int

然而,却不知道这种推断方式是implicit,如果变成下面的代码就不会通过编译了

#include <iostream>

template<typename T> struct Foo
{
  Foo(int) { std::cout << "int\n"; }
  Foo(double) { std::cout << "double\n"; }
};

int main()
{
  Foo fi(233);
  Foo fd(2.33);
}

期望的是fi(233)会调用第一个构造函数而fd(2.33)则调用第二个,然而编译器却拒绝编译上面的代码! 这时,我们需要显式地(explicitly)给出推断指引
Explicit Deduction Guide

如你所见,上图中出现了之前一模一样的语法 Foo(int) -> Foo<int>,这就是explicit deduction guide,上面那个

template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;

只不过多了template parameter pack而已, 当然,图中的推断也可以使用template<typename T> Foo(T) -> Foo<T>

PS. 目前来看这个东西,主流编译器中只有GCC7才支持。。。

参考与引用


转载请注明:Serenity » cpp 日常

上一篇

下一篇