是否可以创建一个带有可变数量参数的模板函数,例如,在此Vector< T, C >
类构造函数中:
template < typename T, uint C >
Vector< T, C >::Vector( T, ... )
{
va_list arg_list;
va_start( arg_list, C );
for( uint i = 0; i < C; i++ ) {
m_data[ i ] = va_arg( arg_list, T );
}
va_end( arg_list );
}
这几乎可以工作,但如果有人调用Vector< double, 3 >( 1, 1, 1 )
,则只有第一个参数具有正确的值。我怀疑第一个参数是正确的,因为它在函数调用期间被强制转换为double
,而其他参数被解释为int
s然后这些位被填充到double
中。调用Vector< double, 3 >( 1.0, 1.0, 1.0 )
可获得所需的结果。有没有一种首选的方式来做这样的事情?
答案 0 :(得分:9)
template < typename T >
Vector< T >::Vector( T )
{ ... }
template < typename T, uint C >
Vector< T, C >::Vector( T t, C c1 )
{ ... }
template < typename T, uint C >
Vector< T, C >::Vector( T t, C c1, C c2 )
{ ... }
template < typename T, uint C >
Vector< T, C >::Vector( T t, C c1, C c2, C c3 )
{ ... }
宏生成一些设定数量(通常约为10个)版本,并提供一种机制来在扩展构造之前更改参数的最大数量。
基本上,这是一个真正的痛苦,这就是为什么C ++ 0x引入了可变长度模板参数和委托方法,可以让你干净(安全)地完成这项工作。在此期间,您可以使用宏来执行此操作,也可以尝试使用支持(部分)这些新实验功能的C ++编译器。 GCC对此很好。
请注意,由于C ++ 0x实际上还没有出现,所以事情仍然会发生变化,而且您的代码可能与标准的最终版本不同步。此外,即使在标准出来之后,也会有5年左右的时间,许多编译器只会部分支持标准,因此您的代码将不会非常便携。
答案 1 :(得分:2)
这段代码看起来很危险,我认为你对它不起作用的原因进行了分析,编译器在调用时无法知道:
Vector< double, 3 >( 1, 1, 1 )
那些应该作为双打传递。
我会将构造函数更改为:
Vector< T, C >::Vector(const T(&data)[C])
而是,让用户将参数作为数组传递。另一种丑陋的解决方案是这样的:
template < typename T, uint C >
Vector< T, C >::Vector(const Vector<T, C - 1>& elements, T extra) {
}
并像这样调用它(使用某些typedef):
Vector3(Vector2(Vector1(1), 1), 1);
答案 2 :(得分:2)
你可以做你想做的事,但不要做,因为它不是类型安全的。最好传递T
的向量或包含这些值的一对迭代器。
template < typename T, uint C >
Vector< T, C >::Vector(int N, ... )
{
assert(N < C && "Overflow!");
va_list arg_list;
va_start(arg_list, N);
for(uint i = 0; i < N; i++) {
m_data[i] = va_arg(arg_list, T);
}
va_end(arg_list);
}
Vector<int> v(3, 1, 2, 3);
这可以更好地解决,因为无论如何所有元素都是同质的。
template < typename Iter, uint C >
Vector< T, C >::Vector(Iter begin, Iter end)
{
T *data = m_data;
while(begin != end)
*data++ = *begin++;
}
int values[] = { 1, 2, 3 };
Vector<int> v(values, values + 3);
当然,您必须确保m_data
中有足够的位置。
答案 3 :(得分:0)
TypeList是否符合您的需求?
答案 4 :(得分:0)
在C ++ 0x中(实际上应该称为C ++ 1x),你可以使用模板变量以类型安全的方式实现你想要的东西(你甚至不需要指定参数的数量!)。但是,在当前版本的C ++(ISO C ++ 1998 with 2003修订版)中,没有办法完成你想要的。您可以推迟或执行Boost所做的操作,即使用preprocessor macro magic使用不同数量的参数重复构造函数的定义,直到硬编码但大的限制。鉴于Boost.Preprocessor有点复杂,你可以自己定义以下所有内容:
Vector<T,C>::Vector(); Vector<T,C>::Vector(const T&); Vector<T,C>::Vector(const T&, const T&); // ...
由于上述手工操作很痛苦,但您可以编写一个脚本来生成它。
答案 5 :(得分:0)
std::tr1::array
(看起来与你的相似)没有定义构造函数,可以初始化为聚合(?)
std::tr1::array<int, 10> arr = {{ 1, 2, 3, 4, 5, 6 }};
您还可以查看Boost.Assignment库。
例如构造函数可以是
template < typename T, uint C >
template < typename Range >
Vector< T, C >::Vector( const Range& r )
和使用
创建的实例Vector<int, 4> vec(boost::assign::cref_list_of<4>(1)(3)(4)(7));
答案 6 :(得分:0)
您可以使用variadic,variadic表示带有变量参数的模板。more
答案 7 :(得分:0)
构造函数中的变量参数的问题是:
所以“正确”的代码(MS)可能是:
template < typename T, uint C > __cdecl Vector< T, C >::Vector( T, ... )
但编译器会说:
构造函数/析构函数的非法调用约定(MS C4166)