我对模板不太熟悉。如何编写一个名为get的模板函数,根据模板类型选择从中获取的数组?请参阅以下示例:
struct Foo
{
int iArr[10];
char cArr[10];
// How to pick array here based on template type?
template < typename T >
T get( int idx )
{
// This does NOT work!
switch ( T )
{
case int:
return iArr[ idx ];
case char:
return cArr[ idx ];
}
}
};
// Expected behaviour of get()
Foo foo;
int i = foo.get< int >( 2 );
char c = foo.get< char >( 4 );
答案 0 :(得分:9)
虽然Jason提出的解决方案有效,但由于case
语句中的switch
值1)没有明显的意义(“幻数”),因此它很难用于惯用,并且难以维护2)很容易与switch_value<>
专精中的值不同步。我会建议这样做:
struct Foo {
Foo() : iArr(), cArr() { }
template<typename T>
T get(std::size_t const idx) const {
return Foo::get_dispatcher<T>::impl(*this, idx);
}
private:
int iArr[10];
char cArr[10];
template<typename T>
struct get_dispatcher;
};
template<>
struct Foo::get_dispatcher<int> {
static int impl(Foo const& foo, std::size_t const idx) {
return foo.iArr[idx];
}
};
template<>
struct Foo::get_dispatcher<char> {
static char impl(Foo const& foo, std::size_t const idx) {
return foo.cArr[idx];
}
};
使用Foo::get<>
或int
以外的任何类型调用char
都会产生编译错误。
答案 1 :(得分:8)
您需要添加某种类型的值结构,您可以使用它来获取switch-statement的值。例如:
template<typename T>
struct switch_value {};
template<>
struct switch_value<int>
{
enum { value = 1 };
};
template<>
struct switch_value<char>
{
enum { value = 2 };
};
//then inside you structure Foo
template <typename T>
T get( int idx )
{
switch ( switch_value<T>::value )
{
case 1:
return iArr[ idx ];
case 2:
return cArr[ idx ];
}
}
这里的好处是,如果您使用的类型没有有效值,则会抛出编译器错误,因为switch_value<T>
的默认版本没有定义成员value
,所以如果你没有专门针对特定类型的结构,那么这样的模板实例化将失败。
答案 2 :(得分:1)
这可能对你的例子有点过分,但是如果你真的只需要一次存储一个数组,那么你可以使用boost :: variant类和访问者,例如,
#include <boost/variant.hpp>
#include <iostream>
template< typename T >
class GetVisitor : public boost::static_visitor<T>
{
public:
GetVisitor(int index) : index_(index) {};
template <typename U >
T operator() (U const& vOperand) const
{
return vOperand[index_];
}
private:
int index_;
};
int main ()
{
int iArr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
char cArr[10] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j' };
boost::variant<int*, char*> intVariant(iArr); //- assign integer array to variant
boost::variant<int*, char*> charVariant(cArr); //- assign character array to another variant
int testInt = boost::apply_visitor(GetVisitor<int>(2), intVariant);
char testChar = boost::apply_visitor(GetVisitor<char>(9), charVariant);
std::cout << "returned integer is " << testInt << std::endl;
std::cout << "returned character is " << testChar << std::endl;
return 0;
}
output is:
returned integer is 3
returned character is j
GetVisitor类隐含的变体限制是变体的所有成员必须实现:
T operator[](int)
所以你也可以添加std :: vector和std :: deque作为变体的潜在成员。
答案 3 :(得分:0)
您可以专门化成员函数:
struct foo
{
int iArr[10];
char cArr[10];
template<typename T>
T &get(int ipos) { assert( false && "Foo.get: Invalid type!" ); return T(); }
template<>
int &get<int>(int ipos) { return iArr[ipos]; }
template<>
char &get<char>(int ipos) {return cArr[ipos]; }
// add more specialisations for any other types...
};
适用于msvc ++ 2010.希望这会有所帮助。
Jason建议的开关专业化也应该可以正常工作。
答案 4 :(得分:0)
所有这些答案都太过分了。
template <typename T>
T get( int idx )
{
if ( boost::is_same<T, int>::value)
return *(T*)&iArr[ idx ];
else
return *(T*)&cArr[ idx ];
}
答案 5 :(得分:0)
我认为除了专注于模板功能之外,这就是你想要的:
<。>在.h文件中template < typename T >
struct Foo
{
T arr[10];
T get( int idx )
{
return arr[ idx ];
}
};
你在某处使用它:
Foo<int> foo1;
Foo<char> foo2;
int i = foo1.get( 2 );
char c = foo2.get( 4 );