C++14 возврат множества значений из функции.
От: Voivoid Россия  
Дата: 06.11.18 10:44
Оценка:
В C++14 добавили возможность автоматического вывода типа зачения возвращаемого функций. В качестве возвращаемых типов в том числе могут выступать анонимные типы:

auto foo() {
    int x = 10;
    int y = 20;
    int z = 30;

    struct {
        int x;
        int y;
        int z;
    } ret;

    ret.x = x;
    ret.y = y;
    ret.z = z;

    return ret;
}

void test()
{
    auto r = foo();
    assert( r.x == 10 );
    assert( r.y == 20 );
    assert( r.z == 30 );
}

live sample:

Выглядит полезно и удобно, однако напрягает бойлерплейт в виде обявления структуры и заполнения её полей. Но магия препроцессора ( реализацию см. в следующем live sample ) приходит на помощь и позволяет написать что-то типа такого:

auto foo() {
    int x = 10;
    int y = 20;
    int z = 30;

    RETURN_ANONYMOUS_STRUCT( x, y, z );
}

live sample:



Такие вот мысли возникли. Может кому покажется интересным и пригодится.
с++14 auto return
Re: C++14 возврат множества значений из функции.
От: Анатолий Широков СССР  
Дата: 06.11.18 11:01
Оценка:
Здравствуйте, Voivoid, Вы писали:

V>В C++14 добавили возможность автоматического вывода типа зачения возвращаемого функций. В качестве возвращаемых типов в том числе могут выступать анонимные типы:


А почему не std::tuple https://en.cppreference.com/w/cpp/utility/tuple?

#include <tuple>

auto gather() {
  return std::make_tuple(1, 2, 3);
}

int main() {
  auto[x, y, z] = gather();
}
Отредактировано 06.11.2018 11:04 Анатолий Широков . Предыдущая версия .
Re: C++14 возврат множества значений из функции.
От: reversecode google
Дата: 06.11.18 11:04
Оценка:
https://coliru.stacked-crooked.com/a/0b94f5da02431b3c

struct AA
{
    int x,y,z;
};

auto foo() {
    int x = 10;
    int y = 20;
    int z = 30;
    return AA { x, y, z };
}

int main()
{
    auto r = foo();
    assert( r.x == 10 );
    assert( r.y == 20 );
    assert( r.z == 30 );
    
    std::cout << "ok\n";
}
Re[2]: C++14 возврат множества значений из функции.
От: Voivoid Россия  
Дата: 06.11.18 11:17
Оценка: 1 (1)
Здравствуйте, Анатолий Широков, Вы писали:

АШ>А почему не std::tuple https://en.cppreference.com/w/cpp/utility/tuple?


АШ>
АШ>#include <tuple>

АШ>auto gather() {
АШ>  return std::make_tuple(1, 2, 3);
АШ>}

АШ>int main() {
АШ>  auto[x, y, z] = gather();
АШ>}
АШ>

Это C++17 плюс, что более важно, в случае со structured binding имеется неявная зависимость от порядка следования аргументов. Можно поменять местами аргументы в функции gather и забыть подправить функцию main, что приведет к тому что забиндится не то, что хотелось бы.
Re[2]: C++14 возврат множества значений из функции.
От: Voivoid Россия  
Дата: 06.11.18 11:22
Оценка:
Здравствуйте, reversecode, Вы писали:

R>https://coliru.stacked-crooked.com/a/0b94f5da02431b3c


R>
R>struct AA
R>{
R>    int x,y,z;
R>};


Не, ну это очевидное и всем известное решение. Минус в том, что несколько засоряется namespace и в том, что при будущих изменениях кроме кода возвращающей функции нужно еще и поправить поля структуры.
Re: C++14 возврат множества значений из функции.
От: _NN_ www.nemerleweb.com
Дата: 06.11.18 13:02
Оценка:
Здравствуйте, Voivoid, Вы писали:

V>В C++14 добавили возможность автоматического вывода типа зачения возвращаемого функций. В качестве возвращаемых типов в том числе могут выступать анонимные типы:


Сначала стоит понять чего хотим.
Именованные кортежи ? (Named tuples)

Один из вариантов: http://vitiy.info/named-tuple-for-cplusplus/


auto foo() {
     return make_named_tuple(param("x") = 10, param("y") = 20, param("z") = 30);
}

int main()
{
    auto r = foo();
    assert( r[param("x")] == 10 );
    assert( r[param("y")] == 20 );
    assert( r[param("z")] == 30 );
    
    std::cout << "ok\n";
}


  Полный код
#include <cassert>

#include <utility>
#include <iostream>
#include <tuple>

// Named tuple for C++
// Example code from http://vitiy.info/
// Written by Victor Laskin (victor.laskin@gmail.com)

// Parts of code were taken from: https://gist.github.com/Manu343726/081512c43814d098fe4b

namespace foonathan {
    namespace string_id {
        namespace detail
        {
            using hash_type = std::uint64_t;
            
            constexpr hash_type fnv_basis = 14695981039346656037ull;
            constexpr hash_type fnv_prime = 109951162821ull;
            
            // FNV-1a 64 bit hash
            constexpr hash_type sid_hash(const char *str, hash_type hash = fnv_basis) noexcept
            {
                return *str ? sid_hash(str + 1, (hash ^ *str) * fnv_prime) : hash;
            }
        }
    }
} // foonathan::string_id::detail


    namespace fn_detail {
        
         /// Named parameter (could be empty!)
        template <typename Hash, typename... Ts>
        struct named_param : public std::tuple<std::decay_t<Ts>...> {
            using hash = Hash;                                                              ///< key
            
            named_param(Ts&&... ts) : std::tuple<std::decay_t<Ts>...>(std::forward<Ts>(ts)...){ };        ///< constructor
            
            template <typename P>
            named_param<Hash,P> operator=(P&& p){ return named_param<Hash,P>(std::forward<P>(p)); };
            
            
        };
    
        template <typename Hash>
        using make_named_param = named_param<Hash>;
        
        

        
        /// Named tuple is just tuple of named params
        template <typename... Params>
        struct named_tuple : public std::tuple<Params...>
        {
            
            template <typename... Args>
            named_tuple(Args&&... args) : std::tuple<Args...>(std::forward<Args>(args)...) {}
            
            static const std::size_t error = -1;
            
            template<std::size_t I = 0, typename Hash>
            constexpr typename std::enable_if<I == sizeof...(Params), const std::size_t>::type
            static get_element_index()
            {
                return error;
            }
            
            template<std::size_t I = 0, typename Hash>
            constexpr typename std::enable_if<I < sizeof...(Params), const std::size_t>::type
            static get_element_index()
            {
                using elementType = typename std::tuple_element<I, std::tuple<Params...>>::type;
                //return (typeid(typename elementType::hash) == typeid(Hash)) ? I : get_element_index<I + 1, Hash>();
                return (std::is_same<typename elementType::hash, Hash>::value) ? I : get_element_index<I + 1, Hash>();
            }
            
            template<typename Hash>
            const auto& get() const
            {
                constexpr std::size_t index = get_element_index<0, Hash>();
                static_assert((index != error), "Wrong named tuple key");
                auto& param = (std::get< index >(static_cast<const std::tuple<Params...>&>(*this)));
                return std::get<0>( param );
            }
            
            template<typename NP>
            const auto& operator[](NP&& param)
            {
                return get<typename NP::hash>();
            }
             
        };
        
            

    }
    
    template <typename... Args>
    auto make_named_tuple(Args&&... args)
    {
        return fn_detail::named_tuple<Args...>(std::forward<Args>(args)...);
    }
    
#define param(x) fn_detail::make_named_param< std::integral_constant<foonathan::string_id::detail::hash_type, foonathan::string_id::detail::sid_hash(x)> >{}


auto foo() {
     return make_named_tuple(param("x") = 10, param("y") = 20, param("z") = 30);
}

int main()
{
    auto r = foo();
    assert( r[param("x")] == 10 );
    assert( r[param("y")] == 20 );
    assert( r[param("z")] == 30 );
    
    std::cout << "ok\n";
}


https://coliru.stacked-crooked.com/a/1273c69e85676a7c
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re: C++14 возврат множества значений из функции.
От: Evgeny.Panasyuk Россия  
Дата: 06.11.18 13:21
Оценка:
Здравствуйте, Voivoid, Вы писали:

V>Выглядит полезно и удобно, однако напрягает бойлерплейт в виде обявления структуры и заполнения её полей.


Вот так вполне себе:
auto foo() {
    struct {
        int x;
        int y;
        int z;
    } ret{10,20,30};
    return ret;
}


V>Но магия препроцессора ( реализацию см. в следующем live sample ) приходит на помощь и позволяет написать что-то типа такого:


Можно более общо
Автор: Evgeny.Panasyuk
Дата: 12.10.14
:
auto foo()
{
    return NEW((x,10)(y,20)(z,30));
}
Re: C++14 возврат множества значений из функции.
От: B0FEE664  
Дата: 06.11.18 13:52
Оценка:
Здравствуйте, Voivoid, Вы писали:

V>В C++14 добавили возможность автоматического вывода типа зачения возвращаемого функций. В качестве возвращаемых типов в том числе могут выступать анонимные типы:


V>
V>auto foo() {
V>


Я правильно помню, что эта функция не может не быть inline, если используется в двух и более cpp файлах? Или она рассматривается наравне с шаблонной?
И каждый день — без права на ошибку...
Re[2]: C++14 возврат множества значений из функции.
От: Voivoid Россия  
Дата: 06.11.18 14:59
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Я правильно помню, что эта функция не может не быть inline, если используется в двух и более cpp файлах? Или она рассматривается наравне с шаблонной?

Да, по идее при использовании в более чем одной единице трансляции функция должна быть объявлена как inline ( ну или везде должна быть в анонимном namespace )


Но что-то меня одолевают сомнения на тему того, нет ли тут нарушения ODR в случае с inline. Будет ли возвращаемый функцией анонимый тип считать одинаковым в разных единицах трансляции?
Re: C++14 возврат множества значений из функции.
От: kov_serg Россия  
Дата: 06.11.18 16:43
Оценка:
Здравствуйте, Voivoid, Вы писали:

V>В C++14 добавили возможность автоматического вывода типа зачения возвращаемого функций. В качестве возвращаемых типов в том числе могут выступать анонимные типы:

...
V>Выглядит полезно и удобно, однако напрягает бойлерплейт в виде обявления структуры и заполнения её полей. Но магия препроцессора ( реализацию см. в следующем live sample ) приходит на помощь и позволяет написать что-то типа такого:

Чем это существенно лучше такого кода?
struct foo {
  int x,y,z;
  void operator() () {
    x=10; y=20; z=30;
  }
};

void test() {
  foo r; r();
  assert(r.x==10);
  assert(r.y==20);
  assert(r.z==30);
}
Re[2]: C++14 возврат множества значений из функции.
От: Voivoid Россия  
Дата: 06.11.18 17:35
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>Чем это существенно лучше такого кода?

_>
_>struct foo {
_>  int x,y,z;
_>  void operator() () {
_>    x=10; y=20; z=30;
_>  }
_>};

_>void test() {
_>  foo r; r();
_>  assert(r.x==10);
_>  assert(r.y==20);
_>  assert(r.z==30);
_>}
_>


Я просто хочу вызвать функцию и обращаться к полученному множеству результатов по именам. Альтернатива в виде приседаний с функторами по мне так выглядит менее декларативно.
Re[3]: C++14 возврат множества значений из функции.
От: reversecode google
Дата: 06.11.18 17:55
Оценка:
если ваша идея когда нибудь перейдет в стандарт и без бустовской магии, то замечательно
а пока что я лучше структурку заведу чем пол буста держать под рукой и терять время на компиляции
Re[3]: C++14 возврат множества значений из функции.
От: kov_serg Россия  
Дата: 06.11.18 18:40
Оценка:
Здравствуйте, Voivoid, Вы писали:

V>Я просто хочу вызвать функцию и обращаться к полученному множеству результатов по именам. Альтернатива в виде приседаний с функторами по мне так выглядит менее декларативно.

Нет проблем. есть более декларативные языки.
Re: C++14 возврат множества значений из функции.
От: AeroSun  
Дата: 06.11.18 20:51
Оценка: -1
Стандартное решение — вернуть тюпл (либо сразу инициализировать).
Всё остальное — разновидности говнокода.
Re[2]: C++14 возврат множества значений из функции.
От: B0FEE664  
Дата: 07.11.18 09:18
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>Чем это существенно лучше такого кода?

А есть простой способ такой код сделать методом класса?
И каждый день — без права на ошибку...
Re[3]: C++14 возврат множества значений из функции.
От: kov_serg Россия  
Дата: 07.11.18 09:46
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Здравствуйте, kov_serg, Вы писали:


_>>Чем это существенно лучше такого кода?

BFE>А есть простой способ такой код сделать методом класса?
Конечно же нет
struct A {
  int x;
  struct foo { int y,z; 
    void operator() (A* self) { y=self->x; z=10-y; }
  };
};

...
A a[1];
a->x=3;
A::foo r; r(a);
cout<<a->x<<","<<r.y<<","<<r.z<<endl;
...
Re[4]: C++14 возврат множества значений из функции.
От: B0FEE664  
Дата: 07.11.18 09:58
Оценка:
Здравствуйте, kov_serg, Вы писали:

BFE>>А есть простой способ такой код сделать методом класса?

_>Конечно же нет
Так я и сам могу. Не лаконично и не красиво. Ничем не отличается от внешней функции.
И каждый день — без права на ошибку...
Re[5]: C++14 возврат множества значений из функции.
От: kov_serg Россия  
Дата: 07.11.18 10:06
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Так я и сам могу. Не лаконично и не красиво. Ничем не отличается от внешней функции.

А кто говорил что будет красиво и лаконично?

Меня больше интересует как вы собираетесь экспортивовать из библиотеки "auto foo()" ?
Re[6]: C++14 возврат множества значений из функции.
От: B0FEE664  
Дата: 07.11.18 10:27
Оценка:
Здравствуйте, kov_serg, Вы писали:

BFE>>Так я и сам могу. Не лаконично и не красиво. Ничем не отличается от внешней функции.

_>А кто говорил что будет красиво и лаконично?
Функция возвращающая auto красива, лаконична и может быть методом в отличии от функтора.

_>Меня больше интересует как вы собираетесь экспортивовать из библиотеки "auto foo()" ?

Динамические библиотеки ненавижу, не использую и вам не советую.
И каждый день — без права на ошибку...
Re[7]: C++14 возврат множества значений из функции.
От: kov_serg Россия  
Дата: 07.11.18 11:06
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Функция возвращающая auto красива, лаконична и может быть методом в отличии от функтора.

На вкус и цвет фломастеры разные. Важна не красота, а выразительность. Что-то не получается выразить имеющимся синтаксисом?

_>>Меня больше интересует как вы собираетесь экспортивовать из библиотеки "auto foo()" ?

BFE>Динамические библиотеки ненавижу, не использую и вам не советую.
А статические?
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.