【问题标题】:Enlightening Usage of C++11 decltypeC++11 decltype 的启发式用法
【发布时间】:2011-10-01 23:00:09
【问题描述】:

我刚刚看过 Boris Jabes 的 this really nice talk Rock Hard: C++ Evolving。在关于高阶泛型编程的演讲部分中,他说以下是一个函数示例,该函数在返回类型方面更通用,并导致更少的模板函数重载

template <typename Func>
auto deduce(const Func & f) -> decltype(f())
{..}

然而,这可以使用如下的普通模板语法来实现

template <typename Func>
Func deduce(const Func & f)
{..}

所以我猜这个例子并没有真的展示了decltype 的独特力量。谁能举例说明decltype 的这种更启发用法?

【问题讨论】:

  • 没有。第一个例子意味着deduce&lt;Func&gt;(f) 返回Func 的结果类型。第二个示例意味着deduce&lt;Func&gt;(f) 返回Func。你看出区别了吗?
  • 啊,抱歉,我错过了 decltype 参数中的额外 ()。我的错。

标签: c++ templates c++11 decltype


【解决方案1】:

你的怀疑是错误的。

void f() { }

现在deduce(&amp;f) 的类型为void,但通过您的重写,它的类型为void(*)()。在任何情况下,无论您想获得表达式或声明的类型,都可以使用decltype(注意这两者之间的细微差别。decltype(x) 不一定与decltype((x)) 相同)。

例如,您的标准库实现很可能在某处包含类似的行

using size_t = decltype(sizeof(0));
using ptrdiff_t = decltype((int*)0 - (int*)0);
using nullptr_t = decltype(nullptr);

找出add 的正确返回类型在过去的C++ 中一直是一个具有挑战性的问题。现在这是一个简单的练习。

template<typename A, typename B> 
auto add(A const& a, B const& b) -> decltype(a + b) { return a + b; }

鲜为人知的是,您可以在 :: 之前和伪析构函数名称中使用 decltype

// has no effect
(0).~decltype(0)();

// it and ite will be iterators into an initializer list 
auto x = { 1, 2, 3 };
decltype(x)::iterator it = x.begin(), ite = x.end();

【讨论】:

  • 你能解释一下吗:(0).~decltype(0)();?恐怕我不明白。
  • (0).~decltype(0)();不使用 gcc 编译,但使用 clang。如果将 0 替换为类对象,这将很有用,它将显式调用对象自己的析构函数。所以这是允许的(至少通过clang),以便模板可以使用类对象以及 int 等。请参阅godbolt.org/z/M4NNfN
【解决方案2】:
std::for_each(c.begin(), c.end(), [](decltype (c.front()) val){val*=2;});

没有decltype就无法自动扣除容器c的value_type。

【讨论】:

  • 只有在使用 lambda 时才能做到这一点,因为它们不是多态的(但是,我们希望它们在 C++y 中)。如果你使用的是多态函数对象,它会被自动推导出来。
【解决方案3】:

我使用它的一个地方是我需要创建一个必须与另一个变量具有相同类型的变量。但我不确定将来该类型是否会保持不变。

void foo(int a)//maybe in future type of a changed
{
    decltype(a) b;
    //do something with b
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多