Есть ли способ установить возвращаемое значение?

// VERSION 1
struct Range { int begin, end; };
inline Range getRange()
{
int newBegin, newEnd;
// do calculations
return {newBegin, newEnd};
}
struct Test
{
std::vector<Range> ranges;
inline void intensive()
{
ranges.push_back(getRange());
// or ranges.emplace_back(getRange());
// (gives same performance results)
}
};

// VERSION 2
struct Range { int begin, end; };
struct Test
{
std::vector<Range> ranges;
inline void intensive()
{
int newBegin, newEnd;
// do calculations
ranges.emplace_back(newBegin, newEnd);
}
};

Версия 2 всегда быстрее чем версия 1.

Факт есть, getRange() используется несколькими классами. Если бы я подал заявку версия 2, было бы много дублирования кода.

Кроме того, я не могу пройти ranges как неконстантная ссылка на getRange(), как некоторые другие классы используют std::stack вместо std::vector, Я должен был бы создать многократные перегрузки и иметь больше дублирования кода.

Есть ли общий способ / идиома установите возвращаемое значение?

1

Решение

После нашего обсуждения в комментариях об использовании SFINAE, чтобы разрешить размещение на любом типе контейнера (поддерживает ли он emplace или же emplace_back), вот пример реализации.

Вам просто нужен способ определить, emplace или же emplace_back доступно, и отправьте вызов соответственно. Для этого мы будем использовать SFINAE:

namespace detail
{
template<typename T, typename... Args>
auto emplace_impl(int, T& c, Args&&... pp)
-> decltype(c.emplace_back(std::forward<Args>(pp)...))
{
return c.emplace_back(std::forward<Args>(pp)...);
}

template<typename T, typename... Args>
auto emplace_impl(long, T& c, Args&&... pp)
-> decltype(c.emplace(std::forward<Args>(pp)...))
{
return c.emplace(std::forward<Args>(pp)...);
}
} // namespace detail

template<typename T, typename... Args>
auto emplace(T& c, Args&&... pp)
-> decltype(detail::emplace_impl(0, c, std::forward<Args>(pp)...))
{
return detail::emplace_impl(0, c, std::forward<Args>(pp)...);
}

Престижность @DyP, который предоставил это много более хорошее и короткое решение C ++ 11 (см. комментарии). Предыдущие черты основанные решения (редакция 3 & 4) были намного более многословны.


Используя это довольно просто:

template<typename Container>
void test_emplace()
{
Container c;
emplace(c, 3);
}

int main()
{
test_emplace<std::queue<int>>();
test_emplace<std::stack<int>>();
test_emplace<std::deque<int>>();
test_emplace<std::list<int>>();
test_emplace<std::vector<int>>();
}

Я позволю тебе преодолеть разрыв между моими test_emplace() пример использования и ваш реальный код, но это не должно быть слишком сложно сейчас. 😉

4

Другие решения

Вот способ, которым вы можете передать код для вставки в GetRange не зная, что вы используете в:

template<typename Emplacer>
void GetRange( Emplacer emplace ) {
int beg, end;
// ...
emplace( beg, end );
}

std::vector<Range> ranges;
inline void intensive()
{
GetRange( [&]( int b, int e ) {
ranges.emplace_back( b, e );
} );
}
3

Нет, вы строят с getRange() в то время как emplace_back сделано ли строительство в vector,

1
По вопросам рекламы [email protected]