#include <array>
#include <cstddef>
#include <tuple>
#include <type_traits>
#include <iostream>
// implementation
namespace detail
{
template < std:: size_t I>
struct visit_impl
{
template < typename Tuple, typename F, typename ...Args >
inline static constexpr int visit( Tuple const & tuple, std:: size_t idx, F fun, Args && ...args ) noexcept( noexcept( fun( std:: get < I - 1U> ( tuple) , std:: forward < Args> ( args) ...) ) && noexcept( visit_impl< I - 1U> :: visit ( tuple, idx, fun, std:: forward < Args> ( args) ...) ) )
{
return ( idx == ( I - 1U) ? ( fun( std:: get < I - 1U> ( tuple) , std:: forward < Args> ( args) ...) , void ( ) , 0 ) : visit_impl< I - 1U> :: visit ( tuple, idx, fun, std:: forward < Args> ( args) ...) ) ;
}
template < typename R, typename Tuple, typename F, typename ...Args >
inline static constexpr R visit( Tuple const & tuple, std:: size_t idx, F fun, Args && ...args ) noexcept( noexcept( fun( std:: get < I - 1U> ( tuple) , std:: forward < Args> ( args) ...) ) && noexcept( visit_impl< I - 1U> :: template visit< R> ( tuple, idx, fun, std:: forward < Args> ( args) ...) ) )
{
return ( idx == ( I - 1U) ? fun( std:: get < I - 1U> ( tuple) , std:: forward < Args> ( args) ...) : visit_impl< I - 1U> :: template visit< R> ( tuple, idx, fun, std:: forward < Args> ( args) ...) ) ;
}
} ;
template <>
struct visit_impl< 0U>
{
// template parameter 'I' reached 0U, which means the runtime index did not exist in the tuple (we could throw an exception, but we'll ignore it here)
template < typename Tuple, typename F, typename ...Args >
inline static constexpr int visit( Tuple const & , std:: size_t , F, Args&& ...) noexcept
{
return 0 ;
}
template < typename R, typename Tuple, typename F, typename ...Args >
inline static constexpr R visit( Tuple const & , std:: size_t , F, Args&& ...) noexcept( noexcept( R{ } ) )
{
static_assert( std:: is_default_constructible < R> :: value , "Explicit return type of visit_at method must be default-constructible" ) ;
return R{ } ;
}
} ;
}
template < typename Tuple, typename F, typename ...Args >
inline constexpr void visit_at( Tuple const & tuple, std:: size_t idx, F fun, Args && ...args ) noexcept( noexcept( detail:: visit_impl < std:: tuple_size < Tuple> :: value > :: visit ( tuple, idx, fun, std:: forward < Args> ( args) ...) ) )
{
detail:: visit_impl < std:: tuple_size < Tuple> :: value > :: visit ( tuple, idx, fun, std:: forward < Args> ( args) ...) ;
}
template < typename R, typename Tuple, typename F, typename ...Args >
inline constexpr R visit_at( Tuple const & tuple, std:: size_t idx, F fun, Args && ...args ) noexcept( noexcept( detail:: visit_impl < std:: tuple_size < Tuple> :: value > :: template visit< R> ( tuple, idx, fun, std:: forward < Args> ( args) ...) ) )
{
return detail:: visit_impl < std:: tuple_size < Tuple> :: value > :: template visit< R> ( tuple, idx, fun, std:: forward < Args> ( args) ...) ;
}
// demo code
int main( int , char ** ) noexcept
{
static constexpr auto const visitor = [ ] ( auto && v) // standard visitor
{
std:: cout << v << std:: endl ;
} ;
static constexpr auto const visitor_with_result = [ ] ( auto && v, int inc = 1 ) - > int // visitor that returns a result (optionally with second parameter)
{
return v + inc;
} ;
static constexpr auto const tup = std:: make_tuple ( 1 , 2 , 3 , 4 , 5 ) ;
static constexpr std:: array < int , 5U> const arr{ 6 , 7 , 8 , 9 , 10 } ;
for ( int i = 0 ; i < 5 ; ++ i)
{
visit_at( tup, i, visitor) ; // call standard visitor on tuple
}
std:: cout << std:: endl ;
for ( int i = 0 ; i < 5 ; ++ i)
{
std:: cout << visit_at< int > ( tup, i, visitor_with_result) << std:: endl ; // call visitor with result using default second parameter
}
std:: cout << std:: endl ;
for ( int i = 0 ; i < 5 ; ++ i)
{
std:: cout << visit_at< int > ( arr, i, visitor_with_result, 10 ) << std:: endl ; // call visitor with result using explicit second parameter and array instead of tuple
}
return 0 ;
}
I2luY2x1ZGUgPGFycmF5PgojaW5jbHVkZSA8Y3N0ZGRlZj4KI2luY2x1ZGUgPHR1cGxlPgojaW5jbHVkZSA8dHlwZV90cmFpdHM+CiNpbmNsdWRlIDxpb3N0cmVhbT4KCi8vIGltcGxlbWVudGF0aW9uCgpuYW1lc3BhY2UgZGV0YWlsCnsKICAgIHRlbXBsYXRlPHN0ZDo6c2l6ZV90IEk+CiAgICBzdHJ1Y3QgdmlzaXRfaW1wbAogICAgewogICAgICAgIHRlbXBsYXRlPHR5cGVuYW1lIFR1cGxlLCB0eXBlbmFtZSBGLCB0eXBlbmFtZSAuLi5BcmdzPgogICAgICAgIGlubGluZSBzdGF0aWMgY29uc3RleHByIGludCB2aXNpdChUdXBsZSBjb25zdCAmdHVwbGUsIHN0ZDo6c2l6ZV90IGlkeCwgRiBmdW4sIEFyZ3MgJiYuLi5hcmdzKSBub2V4Y2VwdChub2V4Y2VwdChmdW4oc3RkOjpnZXQ8SSAtIDFVPih0dXBsZSksIHN0ZDo6Zm9yd2FyZDxBcmdzPihhcmdzKS4uLikpICYmIG5vZXhjZXB0KHZpc2l0X2ltcGw8SSAtIDFVPjo6dmlzaXQodHVwbGUsIGlkeCwgZnVuLCBzdGQ6OmZvcndhcmQ8QXJncz4oYXJncykuLi4pKSkKICAgICAgICB7CiAgICAgICAgICAgIHJldHVybiAoaWR4ID09IChJIC0gMVUpID8gKGZ1bihzdGQ6OmdldDxJIC0gMVU+KHR1cGxlKSwgc3RkOjpmb3J3YXJkPEFyZ3M+KGFyZ3MpLi4uKSwgdm9pZCgpLCAwKSA6IHZpc2l0X2ltcGw8SSAtIDFVPjo6dmlzaXQodHVwbGUsIGlkeCwgZnVuLCBzdGQ6OmZvcndhcmQ8QXJncz4oYXJncykuLi4pKTsKICAgICAgICB9CgogICAgICAgIHRlbXBsYXRlPHR5cGVuYW1lIFIsIHR5cGVuYW1lIFR1cGxlLCB0eXBlbmFtZSBGLCB0eXBlbmFtZSAuLi5BcmdzPgogICAgICAgIGlubGluZSBzdGF0aWMgY29uc3RleHByIFIgdmlzaXQoVHVwbGUgY29uc3QgJnR1cGxlLCBzdGQ6OnNpemVfdCBpZHgsIEYgZnVuLCBBcmdzICYmLi4uYXJncykgbm9leGNlcHQobm9leGNlcHQoZnVuKHN0ZDo6Z2V0PEkgLSAxVT4odHVwbGUpLCBzdGQ6OmZvcndhcmQ8QXJncz4oYXJncykuLi4pKSAmJiBub2V4Y2VwdCh2aXNpdF9pbXBsPEkgLSAxVT46OnRlbXBsYXRlIHZpc2l0PFI+KHR1cGxlLCBpZHgsIGZ1biwgc3RkOjpmb3J3YXJkPEFyZ3M+KGFyZ3MpLi4uKSkpCiAgICAgICAgewogICAgICAgICAgICByZXR1cm4gKGlkeCA9PSAoSSAtIDFVKSA/IGZ1bihzdGQ6OmdldDxJIC0gMVU+KHR1cGxlKSwgc3RkOjpmb3J3YXJkPEFyZ3M+KGFyZ3MpLi4uKSA6IHZpc2l0X2ltcGw8SSAtIDFVPjo6dGVtcGxhdGUgdmlzaXQ8Uj4odHVwbGUsIGlkeCwgZnVuLCBzdGQ6OmZvcndhcmQ8QXJncz4oYXJncykuLi4pKTsKICAgICAgICB9CiAgICB9OwoKICAgIHRlbXBsYXRlPD4KICAgIHN0cnVjdCB2aXNpdF9pbXBsPDBVPgogICAgewogICAgICAgIC8vIHRlbXBsYXRlIHBhcmFtZXRlciAnSScgcmVhY2hlZCAwVSwgd2hpY2ggbWVhbnMgdGhlIHJ1bnRpbWUgaW5kZXggZGlkIG5vdCBleGlzdCBpbiB0aGUgdHVwbGUgKHdlIGNvdWxkIHRocm93IGFuIGV4Y2VwdGlvbiwgYnV0IHdlJ2xsIGlnbm9yZSBpdCBoZXJlKQogICAgICAgIHRlbXBsYXRlPHR5cGVuYW1lIFR1cGxlLCB0eXBlbmFtZSBGLCB0eXBlbmFtZSAuLi5BcmdzPgogICAgICAgIGlubGluZSBzdGF0aWMgY29uc3RleHByIGludCB2aXNpdChUdXBsZSBjb25zdCYsIHN0ZDo6c2l6ZV90LCBGLCBBcmdzJiYuLi4pIG5vZXhjZXB0CiAgICAgICAgewogICAgICAgICAgICByZXR1cm4gMDsKICAgICAgICB9CgogICAgICAgIHRlbXBsYXRlPHR5cGVuYW1lIFIsIHR5cGVuYW1lIFR1cGxlLCB0eXBlbmFtZSBGLCB0eXBlbmFtZSAuLi5BcmdzPgogICAgICAgIGlubGluZSBzdGF0aWMgY29uc3RleHByIFIgdmlzaXQoVHVwbGUgY29uc3QmLCBzdGQ6OnNpemVfdCwgRiwgQXJncyYmLi4uKSBub2V4Y2VwdChub2V4Y2VwdChSe30pKQogICAgICAgIHsKICAgICAgICAgICAgc3RhdGljX2Fzc2VydChzdGQ6OmlzX2RlZmF1bHRfY29uc3RydWN0aWJsZTxSPjo6dmFsdWUsICJFeHBsaWNpdCByZXR1cm4gdHlwZSBvZiB2aXNpdF9hdCBtZXRob2QgbXVzdCBiZSBkZWZhdWx0LWNvbnN0cnVjdGlibGUiKTsKICAgICAgICAgICAgcmV0dXJuIFJ7fTsKICAgICAgICB9CiAgICB9Owp9Cgp0ZW1wbGF0ZTx0eXBlbmFtZSBUdXBsZSwgdHlwZW5hbWUgRiwgdHlwZW5hbWUgLi4uQXJncz4KaW5saW5lIGNvbnN0ZXhwciB2b2lkIHZpc2l0X2F0KFR1cGxlIGNvbnN0ICZ0dXBsZSwgc3RkOjpzaXplX3QgaWR4LCBGIGZ1biwgQXJncyAmJi4uLmFyZ3MpIG5vZXhjZXB0KG5vZXhjZXB0KGRldGFpbDo6dmlzaXRfaW1wbDxzdGQ6OnR1cGxlX3NpemU8VHVwbGU+Ojp2YWx1ZT46OnZpc2l0KHR1cGxlLCBpZHgsIGZ1biwgc3RkOjpmb3J3YXJkPEFyZ3M+KGFyZ3MpLi4uKSkpCnsKICAgIGRldGFpbDo6dmlzaXRfaW1wbDxzdGQ6OnR1cGxlX3NpemU8VHVwbGU+Ojp2YWx1ZT46OnZpc2l0KHR1cGxlLCBpZHgsIGZ1biwgc3RkOjpmb3J3YXJkPEFyZ3M+KGFyZ3MpLi4uKTsKfQoKdGVtcGxhdGU8dHlwZW5hbWUgUiwgdHlwZW5hbWUgVHVwbGUsIHR5cGVuYW1lIEYsIHR5cGVuYW1lIC4uLkFyZ3M+CmlubGluZSBjb25zdGV4cHIgUiB2aXNpdF9hdChUdXBsZSBjb25zdCAmdHVwbGUsIHN0ZDo6c2l6ZV90IGlkeCwgRiBmdW4sIEFyZ3MgJiYuLi5hcmdzKSBub2V4Y2VwdChub2V4Y2VwdChkZXRhaWw6OnZpc2l0X2ltcGw8c3RkOjp0dXBsZV9zaXplPFR1cGxlPjo6dmFsdWU+Ojp0ZW1wbGF0ZSB2aXNpdDxSPih0dXBsZSwgaWR4LCBmdW4sIHN0ZDo6Zm9yd2FyZDxBcmdzPihhcmdzKS4uLikpKQp7CiAgICByZXR1cm4gZGV0YWlsOjp2aXNpdF9pbXBsPHN0ZDo6dHVwbGVfc2l6ZTxUdXBsZT46OnZhbHVlPjo6dGVtcGxhdGUgdmlzaXQ8Uj4odHVwbGUsIGlkeCwgZnVuLCBzdGQ6OmZvcndhcmQ8QXJncz4oYXJncykuLi4pOwp9CgovLyBkZW1vIGNvZGUKCmludCBtYWluKGludCwgY2hhcioqKSBub2V4Y2VwdAp7CglzdGF0aWMgY29uc3RleHByIGF1dG8gY29uc3QgdmlzaXRvciA9IFtdKGF1dG8gJiZ2KSAvLyBzdGFuZGFyZCB2aXNpdG9yCgl7CgkJc3RkOjpjb3V0IDw8IHYgPDwgc3RkOjplbmRsOwoJfTsKCXN0YXRpYyBjb25zdGV4cHIgYXV0byBjb25zdCB2aXNpdG9yX3dpdGhfcmVzdWx0ID0gW10oYXV0byAmJnYsIGludCBpbmMgPSAxKSAtPiBpbnQgLy8gdmlzaXRvciB0aGF0IHJldHVybnMgYSByZXN1bHQgKG9wdGlvbmFsbHkgd2l0aCBzZWNvbmQgcGFyYW1ldGVyKQoJewoJCXJldHVybiB2ICsgaW5jOwoJfTsKCXN0YXRpYyBjb25zdGV4cHIgYXV0byBjb25zdCB0dXAgPSBzdGQ6Om1ha2VfdHVwbGUoMSwgMiwgMywgNCwgNSk7CglzdGF0aWMgY29uc3RleHByIHN0ZDo6YXJyYXk8aW50LCA1VT4gY29uc3QgYXJyeyA2LCA3LCA4LCA5LCAxMCB9OwoJZm9yIChpbnQgaSA9IDA7IGkgPCA1OyArK2kpCgl7CgkJdmlzaXRfYXQodHVwLCBpLCB2aXNpdG9yKTsgLy8gY2FsbCBzdGFuZGFyZCB2aXNpdG9yIG9uIHR1cGxlCgl9CglzdGQ6OmNvdXQgPDwgc3RkOjplbmRsOwoJZm9yIChpbnQgaSA9IDA7IGkgPCA1OyArK2kpCgl7CgkJc3RkOjpjb3V0IDw8IHZpc2l0X2F0PGludD4odHVwLCBpLCB2aXNpdG9yX3dpdGhfcmVzdWx0KSA8PCBzdGQ6OmVuZGw7IC8vIGNhbGwgdmlzaXRvciB3aXRoIHJlc3VsdCB1c2luZyBkZWZhdWx0IHNlY29uZCBwYXJhbWV0ZXIKCX0KCXN0ZDo6Y291dCA8PCBzdGQ6OmVuZGw7Cglmb3IgKGludCBpID0gMDsgaSA8IDU7ICsraSkKCXsKCQlzdGQ6OmNvdXQgPDwgdmlzaXRfYXQ8aW50PihhcnIsIGksIHZpc2l0b3Jfd2l0aF9yZXN1bHQsIDEwKSA8PCBzdGQ6OmVuZGw7IC8vIGNhbGwgdmlzaXRvciB3aXRoIHJlc3VsdCB1c2luZyBleHBsaWNpdCBzZWNvbmQgcGFyYW1ldGVyIGFuZCBhcnJheSBpbnN0ZWFkIG9mIHR1cGxlCgl9CglyZXR1cm4gMDsKfQo=