我正在编写一组C ++参数化类,我感兴趣的是其中一些类似于指针的行为。特别是,我希望能够使用具有非常量模板参数的对象创建具有常量模板参数的对象,但不是相反。此示例代码应阐明我的意图:
int main() {
myClass<int> mc_int;
myClass<const int> mc_const_int;
myClass<const int> mc1(mc_const_int); // This should compile.
myClass<int> mc2(mc_int); // This should compile.
myClass<const int> mc3(mc_int); // This should compile.
myClass<int> mc4(mc_const_int); // This should NOT compile.
}
通过创建下一个类层次结构(为了便于阅读而简化),我已经能够实现这种特殊行为:
template <typename T>
class Base {
// ...
protected:
template <typename U>
Base(const Base<U> &obj): _elem(obj._elem) {}
private:
T _elem;
friend class Base<const T>;
};
template <typename T>
class myClass: public Base<T> {
// ...
public:
template <typename U>
myClass(const myClass<U> &obj): Base<const U>(obj) {}
};
它按预期工作,但我对这个设计并不完全满意,因为我只能从构造函数中检测到非常量模板参数,但不能从任何其他成员函数中检测到。
例如,如果我想创建一个带有addAll()
方法的容器类,我希望能够这样做:
int main() {
Container<int> c_int;
c_int.add(new int(1));
c_int.add(new int(2));
c_int.add(new int(3));
Container<const int> c_const_int;
c_const_int.addAll(c_int); // This should compile.
c_int.addAll(c_const_int); // This should NOT compile.
}
但我不知道如何实现以前的行为。有没有人有替代设计的想法来实现我想要做的事情?有谁知道更深入地讨论这个问题的链接?
提前致谢。
答案 0 :(得分:1)
实现此目的的一种方法是通过部分模板专业化。您应该像通常那样为非const
类型定义类:
template <typename T>
struct MyClass {
void f(T&);
};
然后定义专业化
template <typename T>
struct MyClass<T const> {
void f(T&);
void f(T const&);
};
不幸的是,这会导致代码重复,但它应该允许您执行您想要的操作。当然,您也可以使用MyClass<T>&
和MyClass<T const>&
来完成这些功能。
答案 1 :(得分:0)
我有点理解这个问题。您可能可以使用模板专业化。
template <typename T>
class container
{
public:
template<typename U>
void addAll(const container<U>& b ){}
private:
template<>
void addAll(const container<int>&b); //No implementation
};
container<int> b;
....
container<const int> a;
a.addAll(b) ; //Give a link error, I can't understand why vc2010 compile and run this line though
答案 2 :(得分:0)
一种可能性是使用成员函数模板,启用它们以实现所需的组合。
#include <utility>
template <class T, class U>
struct const_convertible;
template <class T>
struct const_convertible<T, T>: std::true_type {};
template <class T>
struct const_convertible<T, const T>: std::true_type {};
template <class T>
struct const_convertible<const T, T>: std::false_type {};
template <class T>
class X
{
public:
X() {}
X(const X&) {} //copy constructor
//conversion constructor as needed
template <class U>
X(const X<U>&, typename std::enable_if<const_convertible<U, T>::value, void>::type* = 0)
{}
template <class U>
typename std::enable_if<const_convertible<U, T>::value, void>::type f(X<U>) {}
};
int main()
{
X<int> mut;
X<const int> con;
X<int> a(mut);
//X<int> b(con);
X<const int> c(mut);
X<const int> d(con);
mut.f(mut);
//mut.f(con);
con.f(mut);
con.f(con);
//X<double> doub;
//doub.f(mut);
}