2012-06-15 35 views
1

对不起,如果这是一个骗局。有很多类似的问题,但似乎没有真正解决这个问题。他们都有点不同。C++单构造模板专精

所以我想实现:考虑一个模板类X<T>。现在,我想要一个额外的构造函数为该模板的特定实例提供额外的空间,比如指针X<T*>。我不想为X<T*>创建一个完整的模板规范,因为X<T*>应该与通常的模板完全一样(并且该模板是巨大的,所以复制粘贴将会是相当复杂的代码),只是它有一个额外的构造函数。我也不想让X<T*>继承自X<T>,因为我不想在这两者之间建立子类型关系。 这可能吗?我试过这样:

template<T> class X{}; 

template<T> X<T*>::X(int i){...} 

但它doesnt编译。这是否有可能?

+0

我不认为这是可能的,只有两种方法我可以看到它完成是你不想做它的两种方法。 –

+0

你总是可以使用静态工厂方法或帮助类,或者作为最后的手段,'X 实例(* ptr);' – Rook

+0

有没有办法将静态工厂用作隐式转换? – gexicide

回答

5

你可以做这样的事情,使用SFINAE

#include <iostream> 
#include <type_traits> 

template<class T> class X{ 
public: 
    X(int i) { 
     init(); 
    } 
private: 
    template<class U = T> 
    typename std::enable_if<std::is_pointer<U>::value>::type init() { 
     std::cout << "It's a pointer!\n"; 
    } 

    template<class U = T> 
    typename std::enable_if<!std::is_pointer<U>::value>::type init() { 
     std::cout << "It's not a pointer!\n"; 
    } 
}; 

int main() { 
    X<int> a(1); 
    X<int*> b(2); 
} 

,输出:

It's not a pointer! 
It's a pointer! 

你不超载的构造,但你实现你想要什么。

请注意,您需要C++ 11才能使用此代码。

编辑:好的,这个代码正是你想要的:

#include <iostream> 
#include <type_traits> 

template<class T> class X{ 
public: 
    template<class U = T, class enabler = typename std::enable_if<std::is_pointer<U>::value, T>::type> 
    X(int i) { 
     std::cout << "It's a pointer!\n"; 
    } 

    template<class U = T, class enabler = typename std::enable_if<!std::is_pointer<U>::value, T*>::type> 
    X() { 
     std::cout << "It's not a pointer!\n"; 
    } 
}; 

int main() { 
    X<int> a; 
    X<int*> b(2); 
} 

仍然输出和以前一样。请注意,这不是一个好设计。根据你的模板参数有一些构造函数很奇怪。这段代码解决了你的问题。

+0

你可能需要'#include '为'enable_if'工作 – Alex

+0

@Vash谢谢,补充说包括:D。 – mfontanini

+0

'template '是什么意思?我是否也可以使用其他东西,比如'template '? – gexicide

0

这是一个使用boost但不需要C++ 11的解决方案。无论哪种情况,X都有一个构造函数,它接受一个参数。当T是一个指针时,它期望的参数是int。当T不是指针时,参数是调用者无法访问的类型。

#include <boost/type_traits.hpp> 

template < typename T > 
class X 
{ 
private: 
    // Declare a private type that will be used to prevent a single-argument 
    // constructor from being callable when T is not a pointer. 
    struct T_must_be_a_pointer; 
public: 
    // Branch at compile-time based on T: 
    // - If T is a pointer, then declare the X(int) constructor. 
    // - If T is not a pointer, then declare X(T_must_be_a_pointer) constructor. 
    explicit X(typename boost::mpl::if_< boost::is_pointer<T>, 
             int, 
             T_must_be_a_pointer >::type i) 
    {} 
}; 

int main() { 
    X<int> a(); 
    // Next line will fail to compile: 
    // X<int> b(1); 
    X<int*> c(2); 
    return 0; 
}