我有以下课程
template<typename T>
class A
{
public:
A(T* d) : ptr(d)
{}
A(const T* d) : ptr(const_cast<T*>(d))
{}
T* Ptr()
{
static_assert(???, "Not allowed when using A(const T* d)");
return ptr;
}
const T* Ptr() const
{
return ptr;
}
private:
T* ptr;
}
如何在编译Ptr()时实现这一点,我知道用于创建此对象的构造函数是什么?我想静态断言当编译Ptr()时使用了consstructor A(T * d):
unsigned char* ptr = new unsigned char[10];
const unsigned char* cptr = new unsigned char[10];
A a(ptr);
A ca(cptr);
a.Ptr(); // Compiles
ca.Ptr(); // Gives compile error
如果程序员在使用const ptr创建类A的对象时调用Ptr(),我想检测编译时间。不允许在使用const ptr创建时调用Foo
我想像这样使用它
void Foo(A<int>& r)
{
....
int* ptr = a.Ptr();
....
}
void Bar(const A<int>& r)
{
...
}
...
A a(ptr);
A ca(cptr);
Bar(a);
Bar(ac);
Foo(a);
Foo(ac);// Gives compile error
答案 0 :(得分:2)
最简单的c ++ 17(我可以告诉你无论如何使用它来推断模板参数类型)方法是使用用户定义的演绎指南和附加标记非类型模板参数:
enum Tag { //
NonConstTag, // Additional tag enum
ConstTag //
}; //
template<typename T, Tag TT>
// ^^^^^^
// Additional non-type template parameter to provide
// different type of A in case of calling const parameter
// constructor
class A
{
public:
A(T* d) : ptr(d)
{}
A(const T* d) : ptr(const_cast<T*>(d))
{}
T* Ptr()
{
static_assert(TT == NonConstTag, "Not allowed when using A(const T* d)");
return ptr;
}
const T* Ptr() const
{
return ptr;
}
private:
T* ptr;
};
template<typename T> //
A(T* d) -> A<T, NonConstTag>; //
// Deduction guides
template<typename T> //
A(const T* d) -> A<T, ConstTag>; //
int main() {
unsigned char* ptr = new unsigned char[10];
const unsigned char* cptr = new unsigned char[10];
A a(ptr);
A ca(cptr);
a.Ptr(); // Compiles
//ca.Ptr(); // Gives compile error
}
修改强>
满足常规正确性的一点改进:
enum Tag {
NonConstTag,
ConstTag
};
template<typename T, Tag TT>
class A
{
public:
A(T* d) : ptr(d), cptr(d)
{}
A(const T* d) : ptr(nullptr), cptr(d)
{}
T* Ptr()
{
static_assert(TT == NonConstTag, "Not allowed when using A(const T* d)");
return ptr;
}
const T* Ptr() const
{
return cptr;
}
private:
T* ptr;
const T* cptr;
};
template<typename T>
A(T* d) -> A<T, NonConstTag>;
template<typename T>
A(const T* d) -> A<T, ConstTag>;
int main() {
unsigned char* ptr = new unsigned char[10];
const unsigned char* cptr = new unsigned char[10];
A a(ptr);
A ca(cptr);
a.Ptr(); // Compiles
//ca.Ptr(); // Gives compile error
}
答案 1 :(得分:0)
如果您有IDE,它可能允许您跳转到与呼叫对应的声明。 (YouCompleteMe在Vim中使用:YcmCompleter GoTo
执行此操作;我相信Visual Studio有F12或Alt-F12,如果我没记错的话。)
除此之外,如果要检测运行时,请设置标志:
template <typename T> class A {
public:
A(T *) {}
A(const T *) : used_const_arg_ctor(true) {}
private:
bool used_const_arg_ctor = false;
void Foo() {
if (used_const_arg_ctor) {
}
}
};
要实际静态断言,请将其设为constexpr类型:
#include <boost/asio.hpp>
template <typename T> class A {
public:
constexpr A(T *) {}
constexpr A(const T *) : used_const_arg_ctor(true) {}
constexpr bool Foo() const {
return used_const_arg_ctor;
}
private:
bool used_const_arg_ctor = false;
};
int main() {
int const i = 42;
constexpr A<int> a(&i);
static_assert(a.Foo(), "is constructed from const pointer");
}
这有用性有限。相反,我建议让T
反映常量:
template <typename T> class A {
public:
A(T*d) : _v(d) {}
constexpr bool IsConst() const { return std::is_const<T>::value; }
private:
T* _v;
};