C++ 在模板中只指定构造函数,保持最佳性能和整洁的界面
1。是否可以专门化模板类中的构造函数? 我举了一个例子:C++ 在模板中只指定构造函数,保持最佳性能和整洁的界面,c++,performance,templates,template-specialization,C++,Performance,Templates,Template Specialization,1。是否可以专门化模板类中的构造函数? 我举了一个例子: // squared matrix class template <unsigned int size> class Matrix { public: // list of lists matrix constructor Matrix(std::initializer_list<std::initializer_list<float>> values); // actual
// squared matrix class
template <unsigned int size>
class Matrix {
public:
// list of lists matrix constructor
Matrix(std::initializer_list<std::initializer_list<float>> values);
// actual static data
float data[size][size];
};
然后我在ctor定义中得到错误:
Matrix<3>::Matrix(std::initializer_list<Vec3> basis_vectors) {
// only accept 3 vectors
assert(basis_vectors.size() == 3);
// column counter
unsigned int j = 0;
for (auto & col : basis_vectors) {
// copy a column (col to data[:][j])
data[0][j] = col[0];
data[1][j] = col[1];
data[2][j] = col[2];
// increase j for column
j++;
}
}
Matrix::Matrix(标准::初始值设定项\u列表基\u向量){
//只接受3个向量
断言(basis_vectors.size()=3);
//列计数器
无符号整数j=0;
用于(自动列:基向量(&C){
//复制列(列到数据[:][j])
数据[0][j]=col[0];
数据[1][j]=列[1];
数据[2][j]=col[2];
//增加柱的j
j++;
}
}
例如“标识符‘数据’未定义”
注意事项:我希望尽可能避免继承。奇怪的模板模式可能很好,但最好也避免使用这些模式(否则,所有内容的可读性都会比现在差)。
不过,我想指出,我的重点是绩效。因此,我正在寻找最快、可能最干净的解决方案(例如,对于必须实例化这些类的用户来说是干净的。这就是为什么我在构造函数中使用初始值设定项列表)
附带问题: 2。专门化构造函数的正确语法是什么? 我指的是:我是否需要在方法名称之前提供
模板
,或者模板
,或者什么都不提供?那么实际的构造函数方法呢?是Matrix()
还是Matrix()
3。有没有一种方法可以允许我的构造函数在实例化对象时使用大括号列表语法(使语法更清晰统一),同时强制使用固定大小的列表?
在我的例子中,我希望有一个构造函数,它只接受3Vec3
(并且在编译时知道这一点,而不使用assert
ing)。但是我宁愿避免签名矩阵(Vec3 a,Vec3 b,Vec3 c)
。这可能吗
4。我想做的事情,即在2D数组中设置列,哪种方法更干净、更友好?
如果这需要完全改变我的数据结构,使用一些整洁的C++11/17/20/无论什么std::something
,使用已经实现nD数组切片的东西,或者自己实现,我准备好做所有这些了
在所有这些事情上,我只是需要一些好的建议。很容易开始写东西,然后陷入所有这些细节,最后什么也没写,感觉有太多的方向可以走,这可能会带来非最佳的、不可读的、痛苦的代码重构:(问题1)
是否可以在模板类中专门化构造函数
我想你在看下面的东西
template <unsigned int s = size,
std::enable_if_t< s == 3u, bool> = true>
Matrix (std::initializer_list<Vec3> values)
{ }
但是这个解决方案不仅接受三个Vec3
,而且还接受一个或两个;构造函数在未显式化时会收到一个由三个Vec3{}
初始化的数组,该数组使用默认构造函数(如果可用)
Matrix<3> m7a {{Vec3{}}};
Matrix<3> m7b {{Vec3{}, Vec3{}}};
Matrix<3> m7c {{Vec3{}, Vec3{}, Vec3{}}};
//Matrix<3> m7d {{Vec3{}, Vec3{}, Vec3{}, Vec3{}}}; // compilation error
矩阵m7a{{Vec3{}};
矩阵m7b{{Vec3{},Vec3{}};
矩阵m7c{{Vec3{},Vec3{},Vec3{}};
//矩阵m7d{{Vec3{},Vec3{},Vec3{},Vec3{};//编译错误
--编辑--
OP提问
1) 该构造函数的实现应该在类定义内部,还是可以/应该在外部(使用什么语法?)
我习惯于在类中定义它,但是如果在类中声明如下
template <unsigned int s = size,
std::enable_if_t< s == 3u, bool> = true>
Matrix (std::initializer_list<Vec3> values);
template=true>
矩阵(std::初始值设定项\列表值);
在类的主体之外定义它,如下所示应该是可行的
template <>
template <>
Matrix<3u>::Matrix (std::initializer_list<Vec3> values)
{ }
模板
模板
矩阵::矩阵(标准::初始值设定项\u列表值)
{ }
2) 这将允许我将任意数量的Vec3传递给构造函数,而我希望在初始化列表中只允许传递3个Vec3。有可能实施这一点吗
我认为不可能通过std::initializer\u list
来强制执行它,因为列表中的元素数不是模板值(如std::array
或C样式的数组)或我们可以使用编译时启用SFINAE的东西
您可以使用基于
Vec3[3]
C样式数组的解决方案(请参见我对问题3的回答),但不幸的是,您也可以接受一个或两个Vec3
另一个选项,尽管与SFINAE不完全相同,但它是使用static\u assert
:
Matrix(std::initializer_list<Vec3>)
{
static_assert(size == 3);
...
}
矩阵(标准::初始值设定项列表)
{
静态_断言(大小==3);
...
}
我不是专家,但我认为可以肯定地说,一般来说,您应该将数据存储为1D数组。然后你的类可以把它呈现为一个2D结构。至于次要问题2,你的语法已经正确了。但是,您不能只专门化类的一部分。类专门化与基模板没有关系。这可能是一个完全不同的类。你必须专门化整个班级。@super你说的“安全”是什么意思?为我写作和处理更舒适?更安全?效率更高?效率更高,也许写和处理起来也更舒服。谢谢。这允许我专门化构造函数,只针对size==3的情况。但我还有一些疑问:1)该构造函数的实现应该在类定义内部,还是可以/应该在外部(使用什么语法?)。2) 这将允许我将任意数量的Vec3传递给构造函数,而我希望在初始化列表中只允许传递3个Vec3。“有可能实现这一点吗?”米歇尔·埃皮科里尼——答案有所改进;希望这有帮助。谢谢。这与使用固定大小的C样式数组相比如何?它们能达到同样的效果吗?他们有副作用吗?我想考虑一下(比如效率、可读性等)?”MichelePiccolini说,
Matrix<3> m7a {{Vec3{}}};
Matrix<3> m7b {{Vec3{}, Vec3{}}};
Matrix<3> m7c {{Vec3{}, Vec3{}, Vec3{}}};
//Matrix<3> m7d {{Vec3{}, Vec3{}, Vec3{}, Vec3{}}}; // compilation error
template <unsigned int s = size,
std::enable_if_t< s == 3u, bool> = true>
Matrix (std::initializer_list<Vec3> values);
template <>
template <>
Matrix<3u>::Matrix (std::initializer_list<Vec3> values)
{ }
Matrix(std::initializer_list<Vec3>)
{
static_assert(size == 3);
...
}