考虑以下课程:
template<typename T> class A{
public:
virtual void foo(const T& v){ m_v = v + 1; }
T& bar(){ return m_v;}
T m_v;
// ... other member functions/variables ...
};
如何修改以便以下代码有效(如果可能,则不需要const_cast
上的p
):
int main(){
A<int*> a;
const int* p = nullptr;
a.foo(p);
a.bar();
A<int>().foo(10);
}
问题在于foo
方法的签名,A
由int*
模板化后,就我所知,foo(int* const&)
。我们希望拥有的内容类似于foo(const int* const&)
。
到目前为止,我考虑为类声明之外的指针类型添加foo
成员函数的A
成员函数的专门实现(如专门用于A<int>::foo
),但是编译器无法将函数定义原型解析为声明的方法。
template<typename T>
void A<T*>::foo(const T* const& ){}
gcc抱怨它是invalid use of incomplete type ‘class A<T*>’
我还考虑为指针类型添加整个类的部分特化,它定义了一个额外的成员重载foo
,它接收const T*
,但我无法理解如何重用基本模板中的其余代码(即不重复所有其他函数的声明和定义,例如bar
)。有没有办法从指针部分特化引用基本模板类,用于继承还是有一个转发调用的成员? (This post通过添加额外的虚拟模板参数来提供解决方案。有没有办法绕过这个?)。
最后,当模板参数是指针时,我还考虑过使用enable_if<is_pointer<T>::value, void>::type foo(const PointedToType*);
为foo
方法添加额外的重载,但是如何才能获得PointedToType
来自T
(当知道T
是指针类型时)?
答案 0 :(得分:3)
对我来说,你只需要一个特征template <typename T>
struct arg_type { using type = T const&; };
template <typename T>
struct arg_type<T*> { using type = T const*; };
template <typename T>
using arg_type_t = typename arg_type<T>::type;
的参数类型:
virtual void foo(arg_type_t<T> arg ) {}
如此使用:
{{1}}
答案 1 :(得分:1)
我不确定这是否是你想要的,但你可以使用std::is_pointer
,std::remove_pointer
和std::conditional
的组合来构建你想要的参数类型。但是,我不知道如何编写函数体来对该参数做有用的事情。
#include <type_traits>
template <typename T>
struct A
{
template <
typename U = T,
typename ArgT = std::conditional_t<
std::is_pointer<U>::value,
const std::remove_pointer_t<U> *,
U>
>
void
foo(const ArgT&)
{
// ...
}
};
我在这里使用C ++ 14类型的元函数。如果您无法使用C ++ 14,请将std::fancy_t< … >
替换为typename std::fancy< … >::type
。
以下内容现在有效:
int
main()
{
{
A<int *> a {};
const int * p {};
a.foo(p);
}
{
A<int> a {};
const int i {};
a.foo(i);
}
}
答案 2 :(得分:0)
您可以使用a
模板参数定义const
,即A<const int*> a;
。那会有用。
template<typename T> class A{
public:
void foo(const T &v){ m = v; }
void bar(T &v){ v = m; }
T m;
// ... other member functions/variables ...
};
int main(){
A<const int*> a;
const int* p = nullptr;
a.foo(p);
a.bar(p);
}