【问题标题】:C++ auto type deduction when declaring variables without initialisation声明变量时没有初始化的 C++ 自动类型推导
【发布时间】:2020-05-17 08:10:50
【问题描述】:

我真的很喜欢 C++ 中的自动类型推导,我可以从函数中获得任意复杂的返回类型,而不必担心调用函数时的类型。

换句话说,类似于:

std::vector<std::map<std::string, std::string>> getCollection() { ... }
auto myMapArray = getCollection();

但是,这似乎只有在编译器可以推断出类型时才有效,例如从函数初始化时。

我经常发现自己只想要一个正确类型的默认构造变量(通常是类成员变量),而不得不这样做让我很痛苦:

std::vector<std::map<std::string, std::string>> getCollection();
std::vector<std::map<std::string, std::string>> m_collection;

在这种情况下。但我知道除了使用typedef 或更现代的using 之外,没有其他方法可以避免使用长类型名称:

typedef std::vector<std::map<std::string, std::string>> VecOfMaps;
using VecOfMaps = std::vector<std::map<std::string, std::string>>;
:
VecOfMaps m_collection;

似乎允许对变量进行类型推导,就好像它是从函数返回的东西一样,例如:

std::vector<std::map<std::string, std::string>> getCollection() { ... }
auto m_collection = asif(getCollection);

您不需要提供参数,因为所有重载都需要返回相同的类型。所以我的问题真的是:

  • 有没有比类型别名更好的方法来做到这一点?
  • asif 解决方案是否有任何明显的缺点(它必须允许模板化函数,但这应该只是一个小扩展)?

【问题讨论】:

  • 您指出了为什么一般来说不可能:“所有重载都需要返回相同的类型”。你必须以某种方式对这些信息进行编码。
  • @Passer,是的,确实如此,但它已经在函数中编码,我不确定为什么我们需要为预期的变量再次编码通过调用该函数来设置。
  • 我认为最好的答案是因为语言是这样设计的。编译器推断您的意图的限制是本地的。想象一下这是在一个类模板中,你可以在成员定义之后任意找到函数。
  • 考虑decltype()会有帮助吗? Demo on coliru
  • @Scheff,如果你想回答这个问题,我怀疑这就是我所追求的。我可以做一个decltype(fn()) variable; 没有类型别名,还是我需要实际创建一个类型别名:using FnType = decltype(fn()); FnType variable;?看起来我可以做前者,但我想确保它是标准的东西,而不仅仅是 gcc 扩展。但是,无论如何,最好将它作为一个答案,这样我就可以接受它并让它可供未来的人搜索。

标签: c++ auto type-deduction


【解决方案1】:

关于您的评论:

似乎允许对变量进行类型推导,就好像它是从函数返回的东西一样,例如:

std::vector<std::map<std::string, std::string>> getCollection() { ... }
auto m_collection = asif(getCollection);

在我看来asif() 听起来有点像decltype()

在这种情况下,它是必需的函数的返回类型,因此应该是

decltype(getCollection()) m_collection;

我必须承认,我对 decltype() 在日常业务中的实际使用经验并不丰富,并且有点摆弄自己(出于好奇),最终得到:

#include <iostream>
#include <map>
#include <string>
#include <vector>

auto func() { return std::vector<std::map<std::string, std::string>>(); }

struct Class {
  typedef decltype(func()) VarType;
  VarType var;
};

int main()
{
  Class obj;
  std::cout << "type of Class::var: " << typeid(obj.var).name() << '\n';
}

输出是:

type of Class::var: St6vectorISt3mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES6_St4lessIS6_ESaISt4pairIKS6_S6_EEESaISD_EE

Live Demo on coliru

到目前为止,一切都很好。


我可以在没有类型别名的情况下创建 decltype(fn()) variable; 吗?

#include <iostream>
#include <map>
#include <string>
#include <vector>

auto func() { return std::vector<std::map<std::string, std::string>>(); }

struct Class {
  decltype(func()) var;
};

int main()
{
  Class obj;
  std::cout << "type of Class::var: " << typeid(obj.var).name() << '\n';
}

输出:

type of Class::var: St6vectorISt3mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES6_St4lessIS6_ESaISt4pairIKS6_S6_EEESaISD_EE

Live Demo on coliru

我必须承认,它是链接的 decltype() 文档中的样本之一,它让我确信这一点。

此外,我想提一下,decltype() 是(类似于sizeof)一个仅编译时类型的评估。因此,如果根本没有 func() 的实现,它甚至可以工作:

#include <iostream>
#include <map>
#include <string>
#include <vector>

std::vector<std::map<std::string, std::string>> func();

struct Class {
  decltype(func()) var;
};

int main()
{
  Class obj;
  std::cout << "type of Class::var: " << typeid(obj.var).name() << '\n';
}

输出:

type of Class::var: St6vectorISt3mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES6_St4lessIS6_ESaISt4pairIKS6_S6_EEESaISD_EE

Live Demo at coliru


看起来我可以做前者,但我想确保它是一个标准的东西,而不仅仅是一个 gcc 扩展。

据我所知,decltype() 实际上是 C++ 标准功能(自 C++11 以来,cppreference.com 中提到的事实对我来说算是“证明”)。

除此之外,我使用最后一个样本来检查它

  • clang 10.0.0 -std=c++11
  • gcc 10.1 -std=c++11
  • msvc v19.24 /std:c++14/std:c++11 不是可用选项。)

CompilerExplorer 上的所有人都通过了这项检查。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多