我需要定义一个接受多个 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
相关问题:
#include <type_traits>
#include <vector>
struct A {
A();
};
static_assert(std::is_convertible_v<double, A> == false);
static_assert(std::is_convertible_v<A, double> == false);
void func(std::vector<double> values);
void func(std::vector<A> as);
int main() {
func({ 4.2 });
}
Run Code Online (Sandbox Code Playgroud)
显然,double
和A
不能相互隐式转换。所以我觉得void func(std::vector<double>)
应该叫。
但不同编译器的结果是不同的: https://godbolt.org/z/c1hW47f4c
GCC 无法编译:
<source>: In function 'int main()':
<source>:14:9: error: call of overloaded 'func(<brace-enclosed initializer list>)' is ambiguous
14 | func({ 4.2 });
| ~~~~^~~~~~~~~
<source>:10:6: note: candidate: 'void func(std::vector<double>)'
10 | void func(std::vector<double> …
Run Code Online (Sandbox Code Playgroud) 我可以简洁地(用大括号)初始化以下 6 种情况中的 5 种:
\n可复制的 | 只移动的 | |
---|---|---|
大批 | 是的 | 是的 |
标准::数组 | 是的 | 是的 |
std::向量 | 是的 | 不 |
一种似乎不起作用的情况是尝试初始化仅移动对象的 std::vector ;无法编译,并显示消息,例如:“错误:调用 \'std::unique_ptr\' 的隐式删除复制构造函数”。
\n为什么是这样?是否有适用于这种情况的替代初始化语法?
\n下面的程序演示了。
\n/*\nclang++ -std=c++14 -W -Wall -Werror question.cc -o question\nclang++ -std=c++17 -W -Wall -Werror question.cc -o question\nclang++ -std=c++20 -W -Wall -Werror question.cc -o question\nclang++ -std=c++2b -W -Wall -Werror question.cc -o question\ng++ -std=c++14 -W -Wall -Werror question.cc -o question\ng++ -std=c++17 -W -Wall -Werror question.cc -o question\ng++ -std=c++20 -W -Wall -Werror question.cc -o …
Run Code Online (Sandbox Code Playgroud) struct Uct
{
std::vector<int> vec{10};
};
Run Code Online (Sandbox Code Playgroud)
上面的代码创建了包含值为 10 的单个元素的向量。但我需要用大小 10 来初始化该向量。像这样:
std::vector<int> vec(10);
Run Code Online (Sandbox Code Playgroud)
如何通过类内初始化来做到这一点?
我正在寻找一种仅使用本机 C++ 语言功能(最高可达 C++17)的解决方案来完成以下任务:
std::array<Type, unsigned int Elem> array_{Type(), // 1 - Call constructor on Type()
Type(), // 2 - ...
... , // 3 - ...
Type()} // Elems - Call the Elem:th Type() constructor
Run Code Online (Sandbox Code Playgroud)
此外,我还希望每个构造函数调用都应该能够接受任意数量的参数。
一个具体的例子是自动编写以下内容:
std::array<std::shared_ptr<int>, 4> array_{std::make_shared<int>(),
std::make_shared<int>(),
std::make_shared<int>(),
std::make_shared<int>()}
Run Code Online (Sandbox Code Playgroud)
即,假设我知道 Type 和 Elem,我想自动化创建大括号括起来的初始值设定项列表的过程,并在该过程中调用 Type:s 构造函数。
有任何想法吗?
更新,我想解决的真正问题如下:
template <typename Type, unsigned int Size>
class Storage {
public:
Storage(std::initializer_list<Type> initializer) : array_{initializer} {}
private:
std::array<Type, Size> array_;
};
void foo(){
Storage<std::shared_ptr<int>, 100> storage(...);
// …
Run Code Online (Sandbox Code Playgroud) std::vector
\xe2\x80\x98s 初始值设定项列表构造函数具有以下形式
vector( std::initializer_list<T> init, const Allocator& alloc = Allocator() );\n
Run Code Online (Sandbox Code Playgroud)\n是什么使得这样的初始化std::vector<string> vec{ \xe2\x80\x9cfoo\xe2\x80\x9d, \xe2\x80\x9cbar\xe2\x80\x9d };
成为可能?为什么构造函数接受一个std::initializer_list<const char*>
,即使std::vectors
\xe2\x80\x98sT
是std::string
?std::initializer_list<const char*>
从到 的转换在哪里以及如何进行std::initializer_list<string>
发生?
c++ implicit-conversion c++11 stdinitializerlist braced-init-list
我用C编写了以下代码
int main(){
int a = {1, 2, 3};
}
Run Code Online (Sandbox Code Playgroud)
看起来分配的变量(在本例中为 a)总是采用第一个数组元素的值。现在我想知道其他数组元素是否被丢弃,或者在a之后写入内存,从而导致缓冲区溢出。
我是计算机科学理学士学位的第一年学生。我收到了教授对我最近提交的作业的评论。我将 int 变量初始化为零:int count{0};
。课程中分配给我们的书只提供了一种使用赋值语句来初始化变量的方法。整数计数=0;
我不记得我在哪里学到的花括号方法来初始化变量。据我的教授说,这不是合法的做法。我的程序在 Atom 和在线调试器上运行没有任何错误。我总是检查我的程序是否有来自两个不同平台的错误。因此,我很困惑是否我的方法是错误的并且被编译器错过了,或者这个方法是合法的但不被认为是标准的。
任何澄清都会有帮助。还有关于调试良好编程实践的任何建议,这样就不会再发生这种情况了,因为我在 10 分作业中丢了 4 分。
考虑:
\n(long long){1};\n
Run Code Online (Sandbox Code Playgroud)\nIt\xe2\x80\x99s 不是C 风格的转换表达式每个 [expr.cast]/1 的
\n\n\n表达式 (T) 强制转换表达式的结果为 T 类型。如果 T 是左值引用类型或对函数类型的右值引用,则结果是左值;如果 T 是对对象类型的右值引用,则结果是 xvalue;否则结果是纯右值。
\n
\n\n强制转换表达式:
\n\n
\n- 一元表达式
\n- ( type-id ) 强制转换表达式
\n
{1}
不应该是强制转换表达式。
它也不是每个 [expr.type.conv]/1 的函数式转换表达式:
\n\n\n简单类型说明符或类型名说明符后跟带括号的可选表达式列表或大括号初始化列表(初始化程序),在给定初始化程序的情况下构造指定类型的值。如果该类型是推导类类型的占位符,则它将替换为本子条款其余部分的类模板推导重载决策所选择的函数的返回类型。否则,如果类型包含占位符类型,则将其替换为由占位符类型推导 ([dcl.type.auto.deduct]) 确定的类型。
\n
\n简单类型说明符:
\n\n
- 嵌套名称说明符 opt 类型名称
\n- 嵌套名称说明符模板简单模板 ID
\n- decl类型说明符
\n- 占位符类型说明符
\n- 嵌套名称说明符 opt 模板名称
\n- 字符
\n- char8_\xc2\xadt
\n- char16_\xc2\xadt
\n …