首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >默认模板参数&未评估上下文中的lambda : bug还是功能?

默认模板参数&未评估上下文中的lambda : bug还是功能?
EN

Stack Overflow用户
提问于 2019-04-02 12:53:50
回答 2查看 948关注 0票数 39

我们考虑使用完全相同的语法创建两种不同类型的目标。用lambdas可以很容易地做到这一点:

代码语言:javascript
复制
auto x = []{};
auto y = []{};
static_assert(!std::is_same_v<decltype(x), decltype(y)>);

但是我们没有使用lambdas,而是在寻找另一种更优雅的语法。这是一些测试。我们首先定义一些工具:

代码语言:javascript
复制
#include <iostream>
#include <type_traits>
#define macro object<decltype([]{})>
#define singleton object<decltype([]{})>

constexpr auto function() noexcept
{
    return []{};
}

template <class T = decltype([]{})>
constexpr auto defaulted(T arg = {}) noexcept
{
    return arg;
}

template <class T = decltype([]{})>
struct object
{
    constexpr object() noexcept {}
};

template <class T>
struct ctad
{
    template <class... Args>
    constexpr ctad(const Args&...) noexcept {}
};

template <class... Args>
ctad(const Args&...) -> ctad<decltype([]{})>;

和下列变量:

代码语言:javascript
复制
// Lambdas
constexpr auto x0 = []{};
constexpr auto y0 = []{};
constexpr bool ok0 = !std::is_same_v<decltype(x0), decltype(y0)>;

// Function
constexpr auto x1 = function();
constexpr auto y1 = function();
constexpr bool ok1 = !std::is_same_v<decltype(x1), decltype(y1)>;

// Defaulted
constexpr auto x2 = defaulted();
constexpr auto y2 = defaulted();
constexpr bool ok2 = !std::is_same_v<decltype(x2), decltype(y2)>;

// Object
constexpr auto x3 = object();
constexpr auto y3 = object();
constexpr bool ok3 = !std::is_same_v<decltype(x3), decltype(y3)>;

// Ctad
constexpr auto x4 = ctad();
constexpr auto y4 = ctad();
constexpr bool ok4 = !std::is_same_v<decltype(x4), decltype(y4)>;

// Macro
constexpr auto x5 = macro();
constexpr auto y5 = macro();
constexpr bool ok5 = !std::is_same_v<decltype(x5), decltype(y5)>;

// Singleton
constexpr singleton x6;
constexpr singleton y6;
constexpr bool ok6 = !std::is_same_v<decltype(x6), decltype(y6)>;

以及以下测试:

代码语言:javascript
复制
int main(int argc, char* argv[])
{
    // Assertions
    static_assert(ok0); // lambdas
    //static_assert(ok1); // function
    static_assert(ok2); // defaulted function
    static_assert(ok3); // defaulted class
    //static_assert(ok4); // CTAD
    static_assert(ok5); // macro
    static_assert(ok6); // singleton (macro also)

    // Display
    std::cout << ok1 << std::endl;
    std::cout << ok2 << std::endl;
    std::cout << ok3 << std::endl;
    std::cout << ok4 << std::endl;
    std::cout << ok5 << std::endl;
    std::cout << ok6 << std::endl;

    // Return
    return 0;
}

这是用GCC的当前主干版本编译的,带有选项-std=c++2a。参见编译器资源管理器中的结果这里

事实上,ok0ok5ok6的工作并不令人惊讶。然而,ok2ok3trueok4并不是非常令人惊讶的事实。

  • 有人能解释一下ok3 true但是ok4 false的规则吗?
  • 这真的是它应该如何工作的吗,或者这是一个关于实验特性的编译器错误(在未评估的上下文中是lambdas)?(非常欢迎参考标准或C++提案)

注意:我真的希望这是一个特性,而不是一个bug,只是因为它使一些疯狂的想法可以实现。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-05-13 21:00:33

有人能解释一下使ok3成为真而ok4是假的规则吗?

ok3是真的,因为使用lambdas类型作为默认类型。

lambda表达式的类型(它也是闭包对象的类型) 是独一无二的,未命名的非联合类类型,

因此,object的默认模板类型、macrosingltone的模板参数类型在每次安装后总是不同的。但是,对于函数function调用,返回的lambda是唯一的,它的类型也是唯一的。模板函数ctad只对参数具有模板,但返回值是唯一的。如果重写功能为:

代码语言:javascript
复制
template <class... Args, class T =  decltype([]{})>
ctad(const Args&...) -> ctad<T>;

在这种情况下,每次实例化后返回类型都会不同。

票数 2
EN

Stack Overflow用户

发布于 2019-04-17 23:49:51

对于ok2函数参数类型(T)取决于指定的模板参数。对于ok3,ctor不是模板。

对于ok4,两个扣减都依赖于相同的参数类型列表(在本例中为空),并且由于这个原因,扣减只发生一次。模板实例化和演绎是不同的东西。对于相同的参数类型列表,只发生一次,而对所有使用都进行实例化。

看看这段代码(https://godbolt.org/z/ph1Wk2)。如果用于扣减的参数不同,则会发生单独的扣减。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55475338

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档