我正在尋找一種方法來識別模板類定義中的基元類型。識別模板中的基元類型
我的意思是,有這個類:
template<class T>
class A{
void doWork(){
if(T isPrimitiveType())
doSomething();
else
doSomethingElse();
}
private:
T *t;
};
有沒有什麼辦法 「實行」 isPrimitiveType()。
我正在尋找一種方法來識別模板類定義中的基元類型。識別模板中的基元類型
我的意思是,有這個類:
template<class T>
class A{
void doWork(){
if(T isPrimitiveType())
doSomething();
else
doSomethingElse();
}
private:
T *t;
};
有沒有什麼辦法 「實行」 isPrimitiveType()。
UPDATE:由於C++ 11,使用is_fundamental
模板從標準庫:
#include <type_traits>
template<class T>
void test() {
if (std::is_fundamental<T>::value) {
// ...
} else {
// ...
}
}
// Generic: Not primitive
template<class T>
bool isPrimitiveType() {
return false;
}
// Now, you have to create specializations for **all** primitive types
template<>
bool isPrimitiveType<int>() {
return true;
}
// TODO: bool, double, char, ....
// Usage:
template<class T>
void test() {
if (isPrimitiveType<T>()) {
std::cout << "Primitive" << std::endl;
} else {
std::cout << "Not primitive" << std::endl;
}
}
爲了節省函數調用的開銷,使用結構:
template<class T>
struct IsPrimitiveType {
enum { VALUE = 0 };
};
template<>
struct IsPrimitiveType<int> {
enum { VALUE = 1 };
};
// ...
template<class T>
void test() {
if (IsPrimitiveType<T>::VALUE) {
// ...
} else {
// ...
}
}
正如其他人指出的,你可以節省你的時間我通過你自己來補充,並使用Boost Type Traits Library中的is_fundamental,這看起來完全一樣。
Boost TypeTraits有很多東西。
假設'原始類型'是指內置類型,您可以執行一系列模板專業化。您的代碼將變爲:
template<class T>
struct A{
void doWork();
private:
T *t;
};
template<> void A<float>::doWork()
{
doSomething();
}
template<> void A<int>::doWork()
{
doSomething();
}
// etc. for whatever types you like
template<class T> void A<T>::doWork()
{
doSomethingElse();
}
下面的例子(先貼在comp.lang.C++主持)說明了使用偏特打印的東西不同,這取決於他們是否是內置的類型。
// some template stuff
//--------------------
#include <iostream>
#include <vector>
#include <list>
using namespace std;
// test for numeric types
//-------------------------
template <typename T> struct IsNum {
enum { Yes = 0, No = 1 };
};
template <> struct IsNum <int> {
enum { Yes = 1, No = 0 };
};
template <> struct IsNum <double> {
enum { Yes = 1, No = 0 };
};
// add more IsNum types as required
// template with specialisation for collections and numeric types
//---------------------------------------------------------------
template <typename T, bool num = false> struct Printer {
void Print(const T & t) {
typename T::const_iterator it = t.begin();
while(it != t.end()) {
cout << *it << " ";
++it;
}
cout << endl;
}
};
template <typename T> struct Printer <T, true> {
void Print(const T & t) {
cout << t << endl;
}
};
// print function instantiates printer depoending on whether or
// not we are trying to print numeric type
//-------------------------------------------------------------
template <class T> void MyPrint(const T & t) {
Printer <T, IsNum<T>::Yes> p;
p.Print(t);
}
// some test types
//----------------
typedef std::vector <int> Vec;
typedef std::list <int> List;
// test it all
//------------
int main() {
Vec x;
x.push_back(1);
x.push_back(2);
MyPrint(x); // prints 1 2
List y;
y.push_back(3);
y.push_back(4);
MyPrint(y); // prints 3 4
int z = 42;
MyPrint(z); // prints 42
return 0;
}
這有幫助,謝謝! – Ben 2009-02-24 08:43:55
它不能完全按照你問的方式完成。 這裏是它是如何做:
template<class T>
class A{
void doWork(){
bool isPrimitive = boost::is_fundamental<T>::value;
if(isPrimitive)
doSomething();
else
doSomethingElse();
}
private:
T *t;
};
如果你把isPrimitive的值直接如果語句中您可能會得到一個警告。這就是爲什麼我引入了一個臨時變量。
另一個類似的例子:
#include <boost/type_traits/is_fundamental.hpp>
#include <iostream>
template<typename T, bool=true>
struct foo_impl
{
void do_work()
{
std::cout << "0" << std::endl;
}
};
template<typename T>
struct foo_impl<T,false>
{
void do_work()
{
std::cout << "1" << std::endl;
}
};
template<class T>
struct foo
{
void do_work()
{
foo_impl<T, boost::is_fundamental<T>::value>().do_work();
}
};
int main()
{
foo<int> a; a.do_work();
foo<std::string> b; b.do_work();
}
您的版本比我的版本更高效一些,但我認爲它沒有補償可讀性成本。 – 2009-02-24 09:56:37
我想這可以做的工作相當不錯,沒有多特:
# include <iostream>
# include <type_traits>
template <class T>
inline bool isPrimitiveType(const T& data) {
return std::is_fundamental<T>::value;
}
struct Foo {
int x;
char y;
unsigned long long z;
};
int main() {
Foo data;
std::cout << "isPrimitiveType(Foo): " << std::boolalpha
<< isPrimitiveType(data) << std::endl;
std::cout << "isPrimitiveType(int): " << std::boolalpha
<< isPrimitiveType(data.x) << std::endl;
std::cout << "isPrimitiveType(char): " << std::boolalpha
<< isPrimitiveType(data.y) << std::endl;
std::cout << "isPrimitiveType(unsigned long long): " << std::boolalpha
<< isPrimitiveType(data.z) << std::endl;
}
,輸出是:
isPrimitiveType(Foo): false
isPrimitiveType(int): true
isPrimitiveType(char): true
isPrimitiveType(unsigned long long): true
有是一個更好的方法 - 使用SFINAE。使用SFINAE,您不必列出每種基本類型。 SFINAE是一種技術,它依賴於當模板專門化失敗時回退到更一般模板的想法。 (它代表「專業化失敗不是錯誤」)。
另外,如果您將某個指針視爲原始類型,那麼您並沒有真正定義它,因此我將爲所有組合創建模板。
// takes a pointer type and returns the base type for the pointer.
// Non-pointer types evaluate to void.
template < typename T > struct DePtr { typedef void R; };
template < typename T > struct DePtr< T * > { typedef T R; };
template < typename T > struct DePtr< T * const > { typedef T R; };
template < typename T > struct DePtr< T * volatile > { typedef T R; };
template < typename T > struct DePtr< T * const volatile > { typedef T R; };
// ::value == true if T is a pointer type
template < class T > struct IsPointer { enum { value = false }; };
template < class T > struct IsPointer < T * > { enum { value = true }; };
template < class T > struct IsPointer < T * const > { enum { value = true }; };
template < class T > struct IsPointer < T * volatile > { enum { value = true }; };
template < class T > struct IsPointer < T * const volatile > { enum { value = true }; };
// ::value == true if T is a class type. (class pointer == false)
template < class T > struct IsClass
{
typedef u8 yes; typedef u16 no;
template < class C > static yes isClass(int C::*);
template < typename C > static no isClass(...);
enum { value = sizeof(isClass<T>(0)) == sizeof(yes) };
};
// ::value == true if T* is a class type. (class == false)
template < class T > struct IsClassPtr
{
typedef u8 yes; typedef u16 no;
template < class C > static yes isClass(int C::*);
template < typename C > static no isClass(...);
enum { value = sizeof(isClass< typename DePtr<T>::R >(0)) == sizeof(yes) };
};
// ::value == true if T is a class or any pointer type - including class and non-class pointers.
template < class T > struct IsClassOrPtr : public IsClass<T> { };
template < class T > struct IsClassOrPtr < T * > { enum { value = true }; };
template < class T > struct IsClassOrPtr < T * const > { enum { value = true }; };
template < class T > struct IsClassOrPtr < T * volatile > { enum { value = true }; };
template < class T > struct IsClassOrPtr < T * const volatile > { enum { value = true }; };
template < class T > struct IsClassOrClassPtr : public IsClass<T> { };
template < class T > struct IsClassOrClassPtr < T * > : public IsClassPtr< T* > { };
template < class T > struct IsClassOrClassPtr < T * const > : public IsClassPtr< T* const > { };
template < class T > struct IsClassOrClassPtr < T * volatile > : public IsClassPtr< T* volatile > { };
template < class T > struct IsClassOrClassPtr < T * const volatile > : public IsClassPtr< T* const volatile > { };
還要注意,相反的情況存在:`std :: is_class`,例如,https://stackoverflow.com/questions/11287043/is-there-a-way-to-specialize-a-template-to-target-primitives – 2017-12-28 14:26:52