2017-02-19 18 views
2

Рассмотрим:позволяет как предварительно вычисленных и компьютерно на лету результаты

template <typename T> 
struct C { 
    std::vector<int> f(const T &t) const { 
     return t.f(); 
    } 
}; 

T::f необходимо вычислить требуемый вектор. Однако некоторые T предварительно вычислили вектор, и мы хотели бы избежать создания копии в таком случае. Вот моя попытка:

struct A { 
    std::vector<int> f() const { 
     std::vector<int> res{10, 20, 30}; // computing the vector. 
     return res; 
    } 
}; 

struct B { 
    const std::vector<int> &f() const { 
     return v_; // returning reference to pre-computed vector. 
    } 
private: 
    std::vector<int> v_{1, 2, 3}; 
}; 

template <typename T> 
struct C { 
    const std::vector<int> &f(const T &t) const { 
     return t.f(); 
    } 
}; 

int main() { 
    using T = B; // For A, we get an error about returning reference to a local. 
    C<T> c; 
    T t; 
    c.f(t); 
    return 0; 
} 

Как комментарий в main указывает, для T=A, приведенный выше код является ошибочным, как он возвращает ссылку на локальную переменную. Как я могу разместить как для T=A, так и T=B, так что предварительно вычисленный вектор B::v_ не копируется?

+0

Ваш код скомпилирован и работает: https://ideone.com/xedSqU – Zefick

+0

@Zefick Он только * появляется * для работы, но, как правильно указывает OP, он возвращает ссылку на локальную переменную, которая является UB. –

+0

Почему вы не можете хранить вычисленный вектор в классе A? Вы решаете проблемы с копированием и синтаксисом. – xinaiz

ответ

4

Make C::f возвращают один и тот же тип, как T::f, с помощью decltype:

template <typename T> 
struct C { 
    auto f(const T &t) const -> decltype(t.f()) { 
     return t.f(); 
    } 
}; 

Это вернет по значению при T = A, и const& когда T = B.

wandbox example

2

Ваша попытка не испытывать то, что он должен. Для того чтобы предварительно рассчитанные результаты были полезными, они должны быть постоянными. Один класс должен выполнять как вычисления, так и хранилище.

Например,

struct A { 
    std::vector<int> const & f() const { 
     if (v_.empty()) { 
      v_ = {10, 20, 30}; // computing the vector. 
     } 
     return v_; 
    } 
private: 
    mutable std::vector<int> v_; 
}; 

Другая архитектура будет хранить все результаты в одном std::map< X, std::vector > (или unordered_map), если есть какой-то тип X, определяющий область функции.

+0

Это правильный подход. – xinaiz