Как создать метод const на основе параметра шаблона?

У меня есть класс с параметром шаблона, и я хочу вызвать его метод. Это выглядит примерно так:

template <typename T>
class Foo {
public:
    void doSomething() {
        for (auto& t: ts) {
            t.doSomething();
        }
    }
private:
    std::vector<T> ts;
};

Это работает, но я хочу сделать doSomething() const, если T сам является const (предполагается, что T::doSomething() тоже будет const). Я нашел возможное решение (на основе этого вопроса), но мне это не нравится.

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();
    }
}

Он отлично работает, но имеет дублирование кода. Есть ли способ избежать этого?

Ответ 1

В то время как не совершенным является обходной путь: у нас есть не const member _doSomething(), где у нас есть код, который является таким же для const и non const, за исключением функции, вызываемой для базового объекта. Поскольку этот член non const, нам нужно const_cast this вызвать его из const Foo.

Так как код внутри _doSomething является const безопасным, безопасно (const_) отбрасывать const.

Ваш код также не будет компилироваться для const, поскольку вы не можете иметь vector of const. Элементы вектора должны быть назначаемыми, которые const types обычно не являются (они действительно не должны: fooobar.com/info/291170/...).
Возможно, вы захотите рассмотреть 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; /info/291170/vector-of-const-objects-giving-compile-error/1440009#1440009
    T test;
};

int main()
{
    Foo<Bar> nonConstInst;
    Foo<const Bar> ConstInst;

    nonConstInst.doSomething();
    ConstInst.doSomething();
    return 0;
}