I have a class with a template parameter, and I want to call a method of it. It looks something like this:
template <typename T>
class Foo {
public:
void doSomething() {
for (auto& t: ts) {
t.doSomething();
}
}
private:
std::vector<T> ts;
};
This works, but I want to make doSomething()
const if T
itself is const (it is assumed that T::doSomething()
will be const too). I found a possible solution (based on this question), but I don't like it.
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();
}
}
It works fine, but it has a code duplication. Is there any way to avoid it?
While not perfect here is a workaround: we have a non const member _doSomething()
where we have the code that is the same for const and non const, except the function called on the underlying object. Since this member is non const
we have to const_cast
this
to call it from a const Foo.
Since the code inside _doSomething
is const safe, it is safe to (const_)cast const
away.
Your code also will not compile for const, since you can not have a vector
of const
. A vector's elements must be assignable, which const types
are typically not (they really should not, however: https://stackoverflow.com/a/17313104/258418).
You might want to consider std::vector<T*>
rather than std::vector<T>
. (I.e. store pointers rather than the objects in the vector)
#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; https://stackoverflow.com/a/17313104/258418
T test;
};
int main()
{
Foo<Bar> nonConstInst;
Foo<const Bar> ConstInst;
nonConstInst.doSomething();
ConstInst.doSomething();
return 0;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With