2016-11-13 4 views
0

Я играл с C++ 17/C++ 1Z особенности apply и invoke немного В конце концов я хотел использовать apply в результате equal_range непосредственно , как это:Как сделать std :: distance a Callable для применения или вызова?

cout << apply(std::distance, data.equal_range(4)) << '\n'; 

Это не компилировать. Я думал, что это потому, что equal_range вернул pair, а не tuple, но, как оказалось, это не тот случай.

Мой более крупный пример компилирует все, если я использую Lambda вместо std::distance. Когда я думаю о причине этого, я предполагаю, что он имеет какое-то отношение к созданию шаблона функции distance. Хмм, жаль, что это не работает без него, потому что я с трудом его создание экземпляра `станд :: расстояние :: итератор>

#include <iostream> 
#include <set> 
#include <functional> // invoke 
#include <experimental/tuple> // apply 

using std::set; using std::cout; 
using std::invoke; 
using std::experimental::apply; 

int main() { 
    set<int> data { 1,2,3,4,5,6 }; 

    // the C++11-way, not possible in one line. 
    auto r = data.equal_range(4); 
    cout << std::distance(r.first, r.second) << '\n'; 

#if 0 // do not work 
    cout << invoke(std::distance, r.first, r.second) << '\n'; 
    cout << apply(std::distance, r) << '\n'; 
    cout << apply(std::distance, make_tuple(r.first, r.second)) << '\n'; 
    cout << apply(std::distance, data.equal_range(4)) << '\n'; 
#endif 

// explicitly instantiate distance: intolerably cumbersome 
cout << apply(std::distance<set<int>::iterator>, data.equal_range(4)) << '\n'; 

    // using a lambda: too long for a single line 
    auto d = [](auto b, auto e) { return std::distance(b, e); }; 
    cout << invoke(d, r.first, r.second) << '\n'; 
    cout << apply(d, r) << '\n'; 
    cout << apply(d, make_tuple(r.first, r.second)) << '\n'; 
    cout << apply(d, data.equal_range(4)) << '\n'; 
} 

Есть ли лучше, более компактный способ использовать apply и invoke с функциями шаблона, такими как distance без явного создания экземпляра или лямбда?

+0

'distance' - это шаблон функции, а не функция шаблона, что является проблемой. ('distance :: iterator>' будет примером функции шаблона.) – ildjarn

+0

@ildjarn Я понимаю, что вы имеете в виду, я должен получить свою терминологию прямо. Хорошо, я знаю, что такое * function template *, но что такое * функция шаблона *, а если не просто * функция *? 'std :: distance' является FT, почему' расстояние :: iterator> 'a TF, а не только F? Потому что он создается из FT? Если да, существует ли разница между TF и ​​F? – towi

+2

"* то, что является функцией шаблона, то, если не просто функция *" Это действительно просто функция, но она имеет меньшее значение в разрешении перегрузки, чем "регулярная" функция, и поэтому стоит различать. (В этом случае нет набора перегрузки, состоящего из обеих функций и функций шаблона, поэтому он здесь не применяется.) – ildjarn

ответ

1
#define OVERLOADS_OF(...)\ 
    [](auto&&...args)->decltype(auto){\ 
    return __VA_ARGS__(decltype(args)(args)...);\ 
    } 

Теперь OVERLOADS_OF(std::distance) является лямбда, который может быть передан std::apply.

Я видел хотя бы одно предложение поставить это (в более синтаксисе, а не на основе макросов) в стандарт; Я не знаю его статуса.

+0

очень приятно. Только два недостатка: a) использует расширение gnu, b) использует макрос. Но, тем не менее, он отметил. – towi

+0

@towi, что GCC расширение? '__VA_ARGS__' - C99. – Yakk

+0

Хорошо, тогда мой поиск в Google показал мне неправильную информацию. Я, вероятно, неверно истолковал [этот ответ] (https://stackoverflow.com/questions/5588855/standard-alternative-to-gccs-va-args-trick). – towi

 Смежные вопросы

  • Нет связанных вопросов^_^