C++ 具有专门构造函数的模板类
考虑以下模板化数组定义的人为示例:C++ 具有专门构造函数的模板类,c++,templates,constructor,metaprogramming,C++,Templates,Constructor,Metaprogramming,考虑以下模板化数组定义的人为示例: template <typename t, unsigned int n> class TBase { protected: t m_Data[n]; //... }; template <typename t, unsigned int n> class TDerived : public TBase<t, n> { TDerived() { } }; 模板类TBase { 受
template <typename t, unsigned int n> class TBase
{
protected:
t m_Data[n];
//...
};
template <typename t, unsigned int n> class TDerived : public TBase<t, n>
{
TDerived()
{
}
};
模板类TBase
{
受保护的:
t m_数据[n];
//...
};
模板类TDerived:公共TBase
{
t派生的()
{
}
};
我可以专门化此类型,为长度为2的数组提供非默认构造函数,如下所示:
template <typename t> class TDerived<t, 2> : public TBase<t, 2>
{
public:
TDerived(const t& x0, const t& x1)
{
m_Data[0] = x0;
m_Data[1] = x1;
}
};
int main()
{
TDerived<float, 2> Array2D_A(2.0f, 3.0f); //uses specialised constructor
TDerived<float, 3> Array3D_A; //uses default constructor
return 0;
}
模板类TDerived:公共TBase
{
公众:
t推导(常数t&x0、常数t&x1)
{
m_数据[0]=x0;
m_数据[1]=x1;
}
};
int main()
{
t派生阵列2d_A(2.0f,3.0f);//使用专门的构造函数
TDerived Array3D_A;//使用默认构造函数
返回0;
}
是否有其他方法可以创建一个类,该类在编译时根据模板参数约束不同的构造函数选项,而不需要对每个变体进行完整的类专门化
换句话说,我是否有办法在
TBase
类中拥有专业的构造函数,而不需要中间步骤创建TDerived
,同时保留TBase
的功能?我认为从基类派生类与这里的问题无关,这仅仅是一个实现细节。您真正想要的是,是否有一种方法可以部分地专门化成员函数,比如构造函数。你想要这样的吗
template <typename T, int N> class Foo
{
Foo(); // general
template <typename U> Foo<U, 2>(); // specialized, NOT REAL CODE
};
模板类Foo
{
Foo();//一般
模板Foo();//专门化的,不是真正的代码
};
这不管用。你总是要专门化整个班级。原因很简单:在知道存在哪些成员函数之前,必须先知道类的完整类型。考虑下面的简单情况:
template <typename T> class Bar
{
void somefunction(const T&);
};
template <> class Bar<int>
{
double baz(char, int);
};
模板类栏
{
空函数(常数T&);
};
模板类栏
{
双baz(char,int);
};
现在Bar::somefunction()
依赖于T
,但该函数仅在T
不是int
时存在,因为Bar
是一个完全不同的类
或甚至考虑另一个专业化>代码>模板类栏:公共zip {};<代码>--即使是一个类的多态性质在一个专门化中也可能完全不同
因此,提供专门化新成员声明(包括构造函数)的唯一方法是专门化整个类。(您可以专门定义现有函数,请参见@Alf的答案。)对于这一点,我基本上有两种选择:
- 使用变量函数进行构造(即“…”符号),可以使用该函数中的值n从堆栈中获取参数。但是,如果用户提供了正确数量的参数,编译器将不会在编译时进行检查
template<typename T, unsigned int n>
struct Foo {
Foo(...) {
va_list ap;
va_start(ap, n);
for(int j=0; j < n; ++j)
bork[j] = va_arg(ap, T);
va_end(ap);
}
};
vector(2.0f)(3.0f)
。实际上,您可以构建一些东西,至少可以确保用户不会在这里提供太多参数。不过这个机制要复杂一些,如果你愿意,我可以组装一个例子您始终可以专门化一个成员,例如
#include <stdio.h>
template< class Type >
struct Foo
{
void bar() const
{ printf( "Single's bar.\n" ); }
};
template<>
void Foo< double >::bar() const
{ printf( "double's bar.\n" ); }
int main()
{
Foo<int>().bar();
Foo<double>().bar();
}
#包括
模板<类类型>
结构Foo
{
空条()常数
{printf(“单间栏。\n”);}
};
模板
void Foo::bar()常量
{printf(“双精度条。\n”);}
int main()
{
Foo().bar();
Foo().bar();
}
但是你需要的是不同的签名,所以这并不是一个直接专门化成员的例子
一种方法是使用一个参数声明一个构造函数,该参数的类型依赖于模板参数
然后你可以根据自己的需要专门化
Cheers&hth.,由于构造函数是一个函数,您需要完全专门化包含类以解决特定问题。没有出路 但是,函数不能部分专用(在所有编译器中)。因此,假设您知道当
t=int或double
时需要n=2
,那么下面是一个备选方案
template<>
TDerived<int,2>::TDerived()
{
//...
}
template<>
TDerived<double,2>::TDerived()
{
//...
}
模板
TDerived::TDerived()
{
//...
}
模板
TDerived::TDerived()
{
//...
}
等等
[注意:如果您使用MSVC,那么我认为它支持部分专门化;在这种情况下,您可以尝试:
template<typename t>
TDerived<t,2>::TDerived()
{
//...
}
模板
TDerived::TDerived()
{
//...
}
不过,我对此还不够肯定。]您可以在非专用类中给出最常见的定义,并在数组长度上给出
static\u assert
(非C++0x的BOOST\u static\u assert)。这可能被认为是一种黑客行为,但它是解决您的问题的简单方法,而且是安全的
template<typename T, unsigned int n>
struct Foo {
Foo(const T& x) { static_assert(n == 1, "Mooh!"); }
Foo(const T& x1, const T& x2) { static_assert(n == 2, "Mooh!"); }
};
-1“提供成员专门化(包括构造函数)的唯一方法是专门化整个类。”不正确。@Alf:Hm,好的,如果您有成员模板,您可以单独专门化这些模板。但我的意思是“在类参数上专门化成员”。怎么说最好?你可以专门化会员。例如,请参阅我的答案。:-)我明白了,但那是不同的,因为你没有改变签名,所以你是专门定义的。在我的示例中,您无法专门化
模板栏::somefunction(const int&)
,因为它不存在。这应该是准确的…好吧,我误解你了。通过修改文本,我删除了否决票。:-)嗯,除了它已经被移除,我不明白。嗯,一个重要的提示。在OP的问题中有两个模板参数,所以我们需要知道这两个参数才能将其社会化。我已经在我的回答中记录了这一点(可能是MSVC支持部分专门化)。@Alf P.Steinbach@iammilind虽然这是一个潜在的解决方案,但理想情况下我希望对构造函数进行部分专门化——例如,通过指定长度而不是类型TBase(const t&x0){}
,部分专业化如下模板TBase::TBase(const t&x0)template<typename... T, unsigned int n>
Foo<T, n> make_foo(T&&...) {
// figure out the common_type of the argument list
// to our Foo object with setters or as a friend straight to the internals
Foo< std::common_type< T... >::type, sizeof(T) > foo;
// recursive magic to pick the list apart and assign
// ...
return foo;
}