Game
类,将
m_players
存储为数据成员 (
std::list<Player>
),每个玩家都有多个数据成员,其中一个是他们的
m_name
(
std::string
)。实例化游戏时,我希望用户提供玩家的姓名。我希望他们能够使用字符串文字或字符串,所以我认为使用
std::string_view
是这里的最佳实践(对吗?)。我还希望游戏可以与任意数量的玩家一起玩,所以我认为游戏 ctor 参数的
std::initializer_list
是正确的选择(对吗?)。下面你可以找到我认为可以工作的代码(godbolt link),但这给了我尝试初始化的代码行错误
m_players
。
#include <iostream>
#include <string>
#include <list>
struct Player
{
Player (std::string_view name)
: m_name{name}
{}
private:
std::string m_name;
};
class Game
{
public:
Game(const std::initializer_list<std::string_view> players)
// error: no matching function for call to 'std::__cxx11::list<Player>::list(<brace-enclosed initializer list>)'
: m_players{players}
{}
private:
std::list<Player> m_players;
};
int main()
{
Game game1{"Ann", "Bob"};
std::string name1{"Ann"};
std::string name2{"Bob"};
Game game2{name1, name2};
}
有两件事有效:
如果我没有弄错的话,无论我使用成员初始值设定项列表还是带有循环的主体,都不应该对性能产生影响,但我仍然很好奇为什么这不起作用。
std::list<T>
由
std::initializer_list<T>
构造,但
Game
采用
std::initializer_list<std::string_view>
。就C++而言,模板类的两个不同模板实例化是完全独立的类型,彼此没有关系。这就是为什么即使
std::initializer_list<std::string_view>
可以从
std::initializer_list<Player>
隐式构造,也无法从
Player
转换为
std::string_view
。请注意,这有效:
std::list<Player> players{"Anna", "Bob"};
虽然这不是:
std::initializer_list<std::string_view> names = {"Anna", "Bob"};
std::list<Player> players{names};
因为在第一个示例中,大括号封闭的初始化列表被转换为std::initializer_list<Player>
,这是
std::list
所需要的。但在第二个示例中,大括号括起来的初始值设定项列表被转换为
std::initializer_list<std::string_view>
,然后无法将其转换回来。按照 @super 的建议并编写
m_players{players.begin(), players.end()}
调用
std::list
的构造函数,该构造函数需要两个迭代器。
std::list
构造函数。 无论我选择什么作为输入类型(字符串或字符串文字),ctor 的输入参数 (
players
) 的类型都是
const std::initializer_list<std::string_view>
(T = std::string_view)。
m_players
的类型为
std::list<Player>
(T = 玩家),如果您检查
std::list
容器的文档,您会发现它提供了多个 ctor,其中一个接受
std::initializier_list<T>
,其中
T
是与
std::list<T>
的类型相同。就我而言,它们是不同的(std::string_view!= Player),这就是问题所在。 解决这个问题的一种方法是使用 @super 提议的不同的 ctor。
: m_players{players.begin(), players.end()}
会打电话给这位演员:
template< class InputIt >
list( InputIt first, InputIt last,
const Allocator& alloc = Allocator() );