如何根据模板参数创建一个方法const?
How to make a method const based on the template parameter?
我有一个带有模板参数的 class,我想调用它的一个方法。它看起来像这样:
template <typename T>
class Foo {
public:
void doSomething() {
for (auto& t: ts) {
t.doSomething();
}
}
private:
std::vector<T> ts;
};
这行得通,但如果 T
本身是常量,我想使 doSomething()
常量(假设 T::doSomething()
也是常量)。我找到了一个可能的解决方案(基于 ),但我不喜欢它。
template <bool enabled = std::is_const<T>::value>
typename std::enable_if<enabled, void>::type
doSomething() const {
for (auto& t: ts) {
t.doSomething();
}
}
template <bool enabled = !std::is_const<T>::value>
typename std::enable_if<enabled, void>::type
doSomething() {
for (auto& t: ts) {
t.doSomething();
}
}
它工作正常,但它有一个代码重复。有什么办法可以避免吗?
虽然不完美,但这里有一个解决方法:我们有一个非 const 成员 _doSomething()
,其中我们的代码对于 const 和非 const 是相同的,除了在底层对象上调用的函数。因为这个成员是 non const
我们必须 const_cast
this
从 const Foo 中调用它。
由于 _doSomething
中的代码是 const 安全的,因此 (const_)cast const
是安全的。
您的代码也不会针对 const 进行编译,因为您不能拥有 const
的 vector
。向量的元素必须是可分配的,const types
通常 不是(它们确实不应该,但是:)。
您可能想要考虑 std::vector<T*>
而不是 std::vector<T>
。 (即存储指针而不是向量中的对象)
#include <iostream>
#include <vector>
using namespace std;
class Bar {
public:
Bar() {}
void doSomething() const {
std::cout << "const" << endl;
}
void doSomething() {
std::cout << "NON const" << endl;
}
};
template <typename T>
class Foo {
void _doSomething() {
/*for (auto& t: ts) {
t.doSomething();
}*/
test.doSomething();
}
public:
Foo()/*T element) : ts({element})*/ {}
template <bool enabled = std::is_const<T>::value>
typename std::enable_if<enabled, void>::type
doSomething() const {
const_cast<typename std::remove_const<Foo<T>>::type*>(this)->_doSomething();
}
template <bool enabled = !std::is_const<T>::value>
typename std::enable_if<enabled, void>::type
doSomething() {
_doSomething();
}
private:
//std::vector<T> ts;
T test;
};
int main()
{
Foo<Bar> nonConstInst;
Foo<const Bar> ConstInst;
nonConstInst.doSomething();
ConstInst.doSomething();
return 0;
}
我有一个带有模板参数的 class,我想调用它的一个方法。它看起来像这样:
template <typename T>
class Foo {
public:
void doSomething() {
for (auto& t: ts) {
t.doSomething();
}
}
private:
std::vector<T> ts;
};
这行得通,但如果 T
本身是常量,我想使 doSomething()
常量(假设 T::doSomething()
也是常量)。我找到了一个可能的解决方案(基于
template <bool enabled = std::is_const<T>::value>
typename std::enable_if<enabled, void>::type
doSomething() const {
for (auto& t: ts) {
t.doSomething();
}
}
template <bool enabled = !std::is_const<T>::value>
typename std::enable_if<enabled, void>::type
doSomething() {
for (auto& t: ts) {
t.doSomething();
}
}
它工作正常,但它有一个代码重复。有什么办法可以避免吗?
虽然不完美,但这里有一个解决方法:我们有一个非 const 成员 _doSomething()
,其中我们的代码对于 const 和非 const 是相同的,除了在底层对象上调用的函数。因为这个成员是 non const
我们必须 const_cast
this
从 const Foo 中调用它。
由于 _doSomething
中的代码是 const 安全的,因此 (const_)cast const
是安全的。
您的代码也不会针对 const 进行编译,因为您不能拥有 const
的 vector
。向量的元素必须是可分配的,const types
通常 不是(它们确实不应该,但是:)。
您可能想要考虑 std::vector<T*>
而不是 std::vector<T>
。 (即存储指针而不是向量中的对象)
#include <iostream>
#include <vector>
using namespace std;
class Bar {
public:
Bar() {}
void doSomething() const {
std::cout << "const" << endl;
}
void doSomething() {
std::cout << "NON const" << endl;
}
};
template <typename T>
class Foo {
void _doSomething() {
/*for (auto& t: ts) {
t.doSomething();
}*/
test.doSomething();
}
public:
Foo()/*T element) : ts({element})*/ {}
template <bool enabled = std::is_const<T>::value>
typename std::enable_if<enabled, void>::type
doSomething() const {
const_cast<typename std::remove_const<Foo<T>>::type*>(this)->_doSomething();
}
template <bool enabled = !std::is_const<T>::value>
typename std::enable_if<enabled, void>::type
doSomething() {
_doSomething();
}
private:
//std::vector<T> ts;
T test;
};
int main()
{
Foo<Bar> nonConstInst;
Foo<const Bar> ConstInst;
nonConstInst.doSomething();
ConstInst.doSomething();
return 0;
}