2010-06-17 72 views
8

我想知道有什麼方法可以對模板類設置限制嗎?
指定在模板中替換的每個類型都必須具有特定的祖先(實現某個接口)。C++模板限制

template < class B > //and every B must be a child of abstract C 
class A { 
public: 
    B * obj; 
    int f() { 
     return B::x + this->obj->f(); 
    } 
}; 

像=>在Haskell

func :: (Ord a, Show b) => a -> b -> c 
+1

爲什麼你認爲你需要這個? – fredoverflow 2010-06-17 14:14:07

+0

可能的[特定基類的C++類模板]的副本(http://stackoverflow.com/questions/2012950/c-class-template-of-specific-baseclass) – SLaks 2010-06-17 14:14:44

+1

sooooo不是初學者的問題:-)。概念實際上頗具爭議。 – 2010-06-17 14:33:30

回答

2

可以use BOOST_STATIC_ASSERT或類似的庫斷言在模板參數的限制。

例如:

#include <limits> 
#include <boost/static_assert.hpp> 

template <class UnsignedInt> 
class myclass 
{ 
private: 
    BOOST_STATIC_ASSERT((std::numeric_limits<UnsignedInt>::digits >= 16) 
         && std::numeric_limits<UnsignedInt>::is_specialized 
         && std::numeric_limits<UnsignedInt>::is_integer 
         && !std::numeric_limits<UnsignedInt>::is_signed); 
public: 
    /* details here */ 
}; 

編輯:對於你的榜樣,你可以寫

template < class B > 
class A { 
    BOOST_STATIC_ASSERT(boost::is_base_of<C, B>); 

public: 
    B * obj; 
    int f() { 
     return B::x + this->obj->f(); 
    } 
}; 
2

你可以使用一個小技巧是這樣的(如果你不想使用升壓) :

class Base 
    { 
    public: 
     static const int TEMPLATE_REQUIRES_BASE_CLASS = 0; 
    }; 

class Correct : public Base 
    { 
    }; 

class Incorrect 
    { 
    }; 

template <typename T> 
class TMPL 
    { 
    static const int TEMPLATE_REQUIRES_BASE_CLASS = T::TEMPLATE_REQUIRES_BASE_CLASS; 
    T *m_t; 
    }; 

void main() 
{ 
TMPL<Correct> one;  // OK 
TMPL<Incorrect> two; // Will not compile 
} 

第一行將編譯。第二個將無法編譯,並給了以下錯誤:

test.cpp 
test.cpp(18) : error C2039: 'TEMPLATE_REQUIRES_BASE_CLASS' : is not a member of 'Incorrect' 
     test.cpp(12) : see declaration of 'Incorrect' 
     test.cpp(25) : see reference to class template instantiation 'TMPL<T>' being compiled 
     with 
     [ 
      T=Incorrect 
     ] 
test.cpp(18) : error C2065: 'TEMPLATE_REQUIRES_BASE_CLASS' : undeclared identifier 
test.cpp(18) : error C2057: expected constant expression 
+0

由於某些未知原因,此代碼在g ++ 4.4下不會失敗。一般來說,我會說在這種情況下,通常使用枚舉: enum {TEMPLATE_REQUIRES_BASE_CLASS = 0}; 這還有一個額外的好處,就是在g ++下沒有達到預期的效果。 – iksemyonov 2010-06-17 15:34:14

+0

@Semen,GCC不合格。標準要求數據成員的聲明在類被隱式實例化時實例化,並且類內的初始化器是聲明的一部分,而不是定義它的定義。然而,該標準略有不清,稱「除非靜態數據成員本身以需要定義靜態數據成員存在的方式使用,否則不會發生靜態數據成員的初始化(以及任何關聯的副作用)。 「 - 這個規則似乎只適用於一個超類初始化(否則沒有意義) – 2010-06-17 16:13:51

+0

@Johannes:謝謝你的解釋,我認爲當它建好的時候我瘋了......但是我猜枚舉仍然是使用更簡單。 (我只是跟隨範德瓦爾德:) – iksemyonov 2010-06-17 16:28:17

6

C++的未來版本將支持這一本身使用的概念(這並沒有使之成爲C++ 11)。來解決這個問題

一種方法是在一個虛擬的模板參數使用專業化:

class C {}; 
template <class B, class dummy=void> 
class A; 

template <class B> 
class A<B, typename enable_if<is_base_and_derived<C, B> >::type> 
{ 
    // class definition here 
}; 

struct D : C {}; 

A<D> d;  // fine 
A<int> n; // compile error - undefined class A<B> 

我就把enable_ifis_base_and_derivedhere獨立的定義。

+0

謝謝,真棒一段代碼 – Andrew 2010-06-17 15:29:26

1

模板是用C++編寫的鴨子。

如果你的類支持模板使用的所有東西,那麼它可以用作模板參數,否則它不能。

如果您的模板,你有類似

C *instance; 

void foo(T *t) 
{ 
    instance = t; 
} 

那麼你執行T是從C(或至少assignement兼容的指針)

3

下使用VC10衍生作品static_assert。我剛剛看到這個使用過,並沒有真正挖掘static_assert實際上做了什麼 - 也許別人可以回答。

#include <type_traits> 

class Base 
{ 

}; 

class Derived : public Base 
{ 

}; 

class SomeRandomClass 
{ 

}; 

template<typename T> 
class A 
{ 
    static_assert(std::tr1::is_base_of<Base, T>::value, "T not derived from Base"); 
}; 



int _tmain(int argc, _TCHAR* argv[]) 
{ 
    argc; argv; 

    // 
    // This will compile 
    A<Derived> a; 

    // 
    // This will throw a compilation error 
    A<SomeRandomClass> b; 

    return 0; 
} 

編譯器輸出端:

1>d:\temp\aaa\aaa\aaa.cpp(25): error C2338: T not derived from Base 
1>   d:\temp\aaa\aaa\aaa.cpp(41) : see reference to class template instantiation 'A<T>' being compiled 
1>   with 
1>   [ 
1>    T=SomeRandomClass 
1>   ]