任何人都可以帮助我解决以下问题吗?
有一个简单的代码:
#include <vector>
struct A {
std::vector<int> vec;
};
void func (A &&a = {}) {}
int main()
{
func();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
当我尝试通过gcc 5.4.0编译它时,我收到错误:
undefined reference to `std::vector<int, std::allocator<int> >::vector()'
Run Code Online (Sandbox Code Playgroud)
令人惊讶的是,但clang编译得很好.此外,如果稍微修改代码,它编译没有任何问题:
#include <vector>
struct A {
std::vector<int> vec;
};
void func (A &&a) {}
int main()
{
func({});
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我真的不明白第一个代码有什么问题.
我理解,给定一个支撑的初始化程序,auto
将推导出一种类型std::initializer_list
,而模板类型推导将失败:
auto var = { 1, 2, 3 }; // type deduced as std::initializer_list<int>
template<class T> void f(T parameter);
f({ 1, 2, 3 }); // doesn't compile; type deduction fails
Run Code Online (Sandbox Code Playgroud)
我甚至知道在C++ 11标准中指定的位置:14.8.2.5/5 bullet 5:
[如果程序有,则这是一个非推导的上下文]一个函数参数,其关联参数是初始化列表(8.5.4),但参数没有std :: initializer_list或者可能是cv-qualified std :: initializer_list的引用类型.[ 例如:
模板void g(T);
克({1,2,3}); //错误:没有推断T的参数
- 结束例子 ]
我不知道或不理解的是为什么存在这种类型演绎行为的差异.C++ 14 CD中的规范与C++ 11中的规范相同,因此标准化委员会可能不会将C++ 11行为视为缺陷.
有人知道为什么auto
推导出支撑初始值设定项的类型,但是不允许使用模板吗?虽然对"这可能是原因"形式的推测性解释很有意思,但我对那些知道为什么标准是按原样编写的人的解释特别感兴趣.
c++ templates c++11 list-initialization template-argument-deduction
基于此代码
struct Foo
{
Foo()
{
cout << "default ctor" << endl;
}
Foo(std::initializer_list<Foo> ilist)
{
cout << "initializer list" << endl;
}
Foo(const Foo& copy)
{
cout << "copy ctor" << endl;
}
};
int main()
{
Foo a;
Foo b(a);
// This calls the copy constructor again!
//Shouldn't this call the initializer_list constructor?
Foo c{b};
_getch();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出是:
默认ctor
复制ctor
复制ctor
在第三种情况下,我将b放入大括号初始化,它应该调用initializer_list <>构造函数.
相反,复制构造函数起带头作用.
你们有人会告诉我这是如何运作的,为什么?
这两个功能之间有什么显着差异吗?
struct Object {
Object(int i) : i{i}
{
}
int i;
};
Object f() { return {1}; }
Object g() { return Object{1}; }
Run Code Online (Sandbox Code Playgroud) 我有以下代码:
class A
{
public:
A(const unsigned int val) : value(val) {}
unsigned int value;
};
int main()
{
int val = 42;
A a(val);
A b{val}; // <--- Warning in GCC, error in Microsoft Visual Studio 2015
return 0;
}
Run Code Online (Sandbox Code Playgroud)
为什么仅在列表初始化使用的情况下才会出现缩小转换警告?
我有以下代码:
#include <initializer_list>
#include <utility>
enum class Classification
{
Unspecified,
Primary,
Secondary
};
class ClassificationMap
{
public:
ClassificationMap(std::initializer_list<std::pair<const Classification, int>> content = {});
};
void foo(ClassificationMap) {}
int main()
{
foo({{Classification::Unspecified, 42}});
}
Run Code Online (Sandbox Code Playgroud)
Visual Studio 2013和2017以及Clang 3.4.1(及以上版本)都编译好了代码.从我的POV来看,它也应该没问题.但是,GCC 5.1拒绝编译它,并出现以下错误:
<source>: In function 'int main()':
<source>:22:44: error: could not convert '{{Unspecified, 42}}' from '<brace-enclosed initializer list>' to 'ClassificationMap'
foo({{Classification::Unspecified, 42}});
Run Code Online (Sandbox Code Playgroud)
(我将正确的标准flag(-std=c++11
)传递给GCC和Clang).
我的代码中是否存在问题,或者这实际上是GCC错误?
补充信息:在我的实际代码中,初始化列表用于初始化类的无序映射成员ClassificationMap
(这就是它的类型就是它的原因).我需要代码在VS2013和GCC 5.1中工作
由代码中的clang 3.5.0和gcc 4.9.1生成的可执行文件
#include <iostream>
struct Foo
{
Foo() { std::cout << "Foo()" << std::endl; }
Foo(int x) { std::cout << "Foo(int = " << x << ")" << std::endl; }
Foo(int x, int y) { std::cout << "Foo(int = " << x << ", int = " << y << ")" << std::endl; }
};
int main() // Output
{ // ---------------------
auto a = Foo(); // Foo()
auto b = Foo(1); // Foo(int = 1)
auto c = …
Run Code Online (Sandbox Code Playgroud) c++ language-lawyer value-initialization list-initialization c++14
考虑这个功能模板:
template <class... T>
void foo (std::tuple<T, char, double> ... x);
Run Code Online (Sandbox Code Playgroud)
此调用有效:
using K = std::tuple<int, char, double>;
foo ( K{1,'2',3.0}, K{4,'5',6.0}, K{7,'8',9.0} );
Run Code Online (Sandbox Code Playgroud)
这个没有:
foo ( {1,'2',3.0}, {4,'5',6.0}, {7,'8',9.0} );
Run Code Online (Sandbox Code Playgroud)
(gcc和clang都抱怨过多论据foo
)
为什么第二次调用有问题?我可以重写声明,foo
以便第二次通话也被接受吗?
模板参数T仅用于实现可变参数.实际类型是已知和固定的,只有参数的数量不同.在现实生活中,类型不同int, char, double
,这只是一个例子.
我不能使用C++ 17.更喜欢C++ 11兼容的解决方案.
我需要定义一个接受多个 3D 坐标作为参数的 C++ 模板。当这些坐标的所有维度都定义为单独的整数变量时,参数列表将变得非常长 - 3 个坐标需要 9 个参数,这使得模板难以使用。
因此,非常希望以使用编译时数组的方式声明模板。它们的默认参数也应该直接在模板声明的位置声明为值,而不是变量名。
经过一些实验,令我惊讶的是,我发现 GCC 13 将接受以下 C++ 程序std=c++20
:
#include <cstdio>
#include <array>
template <
std::array<int, 3> offset = {0, 0, 0}
>
struct Array
{
void operator() (int i, int j, int k)
{
printf("(%d, %d, %d)\n", i + offset[0], j + offset[1], k + offset[2]);
}
};
int main(void)
{
Array arr_default;
arr_default(0, 0, 0);
Array<{1, 1, 1}> arr;
arr(0, 0, 0);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
然而,clang 18 拒绝使用 …
c++ language-lawyer list-initialization braced-init-list c++-templates