我们考虑使用完全相同的语法创建两种不同类型的目标。使用lambdas可以轻松做到这一点:
auto x = []{};
auto y = []{};
static_assert(!std::is_same_v<decltype(x), decltype(y)>);
但是,我们正在寻找另一种更优雅的语法,而不是使用lambda。这是一些测试。我们首先定义一些工具:
#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([]{})>;
和以下变量:
// 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)>;
和以下测试:
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
进行编译的。在编译器资源管理器中查看结果here。
ok0
,ok5
和ok6
工作的事实并不令人惊讶。但是,ok2
和ok3
是true
而ok4
的事实对于我来说并不奇怪。
ok3
true
但ok4
false
的规则吗?注意:我真的希望这是一个功能,而不是错误,只是因为它使一些疯狂的想法变为现实
答案 0 :(得分:2)
有人可以解释使ok3成立的规则吗 ok4错误吗?
ok3是正确的,因为使用lambdas类型作为默认类型。
lambda表达式的类型(这也是闭包的类型 对象) is a unique ,未命名的非工会类类型,
因此,每次声明后,object
的默认模板类型,macro
和singltone
的模板参数类型总是不同的。但是,对于函数function
,调用返回的lambda是唯一的,并且其类型是唯一的。模板函数ctad
仅具有参数模板,但返回值是唯一的。如果将函数重写为:
template <class... Args, class T = decltype([]{})>
ctad(const Args&...) -> ctad<T>;
在这种情况下,每次实例化之后,返回类型都会有所不同。
答案 1 :(得分:0)
取决于指定的模板参数。 ok3 ctor不是模板。
对于ok4,两个推导都依赖于相同的参数类型列表(在这种情况下为空),并且由于推论仅发生一次。模板实例化和推导是不同的事情。对于相同参数类型,列表推导仅发生一次,实例化在所有用法中都会发生。
查看此代码(https://godbolt.org/z/ph1Wk2)。如果要推导的参数不同,则会分别进行推导。