Use (i+1)*2+j for the internal index in the double-buffered case, to avoid branches

This commit is contained in:
Peter Dimov
2021-01-13 02:10:12 +02:00
parent c6186e0a95
commit 453b00dec8

View File

@ -520,11 +520,11 @@ template<class T1, class... T> union variant_storage_impl<mp11::mp_false, T1, T.
T1 first_;
variant_storage<T...> rest_;
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<0>, A&&... a ): first_( std::forward<A>(a)... )
template<class... A> constexpr variant_storage_impl( mp11::mp_size_t<0>, A&&... a ): first_( std::forward<A>(a)... )
{
}
template<std::size_t I, class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<I>, A&&... a ): rest_( mp11::mp_size_t<I-1>(), std::forward<A>(a)... )
template<std::size_t I, class... A> constexpr variant_storage_impl( mp11::mp_size_t<I>, A&&... a ): rest_( mp11::mp_size_t<I-1>(), std::forward<A>(a)... )
{
}
@ -564,18 +564,18 @@ template<class T0, class T1, class T2, class T3, class T4, class T5, class T6, c
variant_storage<T...> rest_;
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<0>, A&&... a ): t0_( std::forward<A>(a)... ) {}
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<1>, A&&... a ): t1_( std::forward<A>(a)... ) {}
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<2>, A&&... a ): t2_( std::forward<A>(a)... ) {}
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<3>, A&&... a ): t3_( std::forward<A>(a)... ) {}
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<4>, A&&... a ): t4_( std::forward<A>(a)... ) {}
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<5>, A&&... a ): t5_( std::forward<A>(a)... ) {}
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<6>, A&&... a ): t6_( std::forward<A>(a)... ) {}
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<7>, A&&... a ): t7_( std::forward<A>(a)... ) {}
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<8>, A&&... a ): t8_( std::forward<A>(a)... ) {}
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<9>, A&&... a ): t9_( std::forward<A>(a)... ) {}
template<class... A> constexpr variant_storage_impl( mp11::mp_size_t<0>, A&&... a ): t0_( std::forward<A>(a)... ) {}
template<class... A> constexpr variant_storage_impl( mp11::mp_size_t<1>, A&&... a ): t1_( std::forward<A>(a)... ) {}
template<class... A> constexpr variant_storage_impl( mp11::mp_size_t<2>, A&&... a ): t2_( std::forward<A>(a)... ) {}
template<class... A> constexpr variant_storage_impl( mp11::mp_size_t<3>, A&&... a ): t3_( std::forward<A>(a)... ) {}
template<class... A> constexpr variant_storage_impl( mp11::mp_size_t<4>, A&&... a ): t4_( std::forward<A>(a)... ) {}
template<class... A> constexpr variant_storage_impl( mp11::mp_size_t<5>, A&&... a ): t5_( std::forward<A>(a)... ) {}
template<class... A> constexpr variant_storage_impl( mp11::mp_size_t<6>, A&&... a ): t6_( std::forward<A>(a)... ) {}
template<class... A> constexpr variant_storage_impl( mp11::mp_size_t<7>, A&&... a ): t7_( std::forward<A>(a)... ) {}
template<class... A> constexpr variant_storage_impl( mp11::mp_size_t<8>, A&&... a ): t8_( std::forward<A>(a)... ) {}
template<class... A> constexpr variant_storage_impl( mp11::mp_size_t<9>, A&&... a ): t9_( std::forward<A>(a)... ) {}
template<std::size_t I, class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<I>, A&&... a ): rest_( mp11::mp_size_t<I-10>(), std::forward<A>(a)... ) {}
template<std::size_t I, class... A> constexpr variant_storage_impl( mp11::mp_size_t<I>, A&&... a ): rest_( mp11::mp_size_t<I-10>(), std::forward<A>(a)... ) {}
~variant_storage_impl()
{
@ -637,11 +637,11 @@ template<class T1, class... T> union variant_storage_impl<mp11::mp_true, T1, T..
T1 first_;
variant_storage<T...> rest_;
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<0>, A&&... a ): first_( std::forward<A>(a)... )
template<class... A> constexpr variant_storage_impl( mp11::mp_size_t<0>, A&&... a ): first_( std::forward<A>(a)... )
{
}
template<std::size_t I, class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<I>, A&&... a ): rest_( mp11::mp_size_t<I-1>(), std::forward<A>(a)... )
template<std::size_t I, class... A> constexpr variant_storage_impl( mp11::mp_size_t<I>, A&&... a ): rest_( mp11::mp_size_t<I-1>(), std::forward<A>(a)... )
{
}
@ -687,18 +687,18 @@ template<class T0, class T1, class T2, class T3, class T4, class T5, class T6, c
variant_storage<T...> rest_;
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<0>, A&&... a ): t0_( std::forward<A>(a)... ) {}
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<1>, A&&... a ): t1_( std::forward<A>(a)... ) {}
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<2>, A&&... a ): t2_( std::forward<A>(a)... ) {}
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<3>, A&&... a ): t3_( std::forward<A>(a)... ) {}
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<4>, A&&... a ): t4_( std::forward<A>(a)... ) {}
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<5>, A&&... a ): t5_( std::forward<A>(a)... ) {}
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<6>, A&&... a ): t6_( std::forward<A>(a)... ) {}
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<7>, A&&... a ): t7_( std::forward<A>(a)... ) {}
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<8>, A&&... a ): t8_( std::forward<A>(a)... ) {}
template<class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<9>, A&&... a ): t9_( std::forward<A>(a)... ) {}
template<class... A> constexpr variant_storage_impl( mp11::mp_size_t<0>, A&&... a ): t0_( std::forward<A>(a)... ) {}
template<class... A> constexpr variant_storage_impl( mp11::mp_size_t<1>, A&&... a ): t1_( std::forward<A>(a)... ) {}
template<class... A> constexpr variant_storage_impl( mp11::mp_size_t<2>, A&&... a ): t2_( std::forward<A>(a)... ) {}
template<class... A> constexpr variant_storage_impl( mp11::mp_size_t<3>, A&&... a ): t3_( std::forward<A>(a)... ) {}
template<class... A> constexpr variant_storage_impl( mp11::mp_size_t<4>, A&&... a ): t4_( std::forward<A>(a)... ) {}
template<class... A> constexpr variant_storage_impl( mp11::mp_size_t<5>, A&&... a ): t5_( std::forward<A>(a)... ) {}
template<class... A> constexpr variant_storage_impl( mp11::mp_size_t<6>, A&&... a ): t6_( std::forward<A>(a)... ) {}
template<class... A> constexpr variant_storage_impl( mp11::mp_size_t<7>, A&&... a ): t7_( std::forward<A>(a)... ) {}
template<class... A> constexpr variant_storage_impl( mp11::mp_size_t<8>, A&&... a ): t8_( std::forward<A>(a)... ) {}
template<class... A> constexpr variant_storage_impl( mp11::mp_size_t<9>, A&&... a ): t9_( std::forward<A>(a)... ) {}
template<std::size_t I, class... A> constexpr explicit variant_storage_impl( mp11::mp_size_t<I>, A&&... a ): rest_( mp11::mp_size_t<I-10>(), std::forward<A>(a)... ) {}
template<std::size_t I, class... A> constexpr variant_storage_impl( mp11::mp_size_t<I>, A&&... a ): rest_( mp11::mp_size_t<I-10>(), std::forward<A>(a)... ) {}
template<class... A> void emplace_impl( mp11::mp_false, mp11::mp_size_t<0>, A&&... a ) { ::new( &t0_ ) T0( std::forward<A>(a)... ); }
template<class... A> void emplace_impl( mp11::mp_false, mp11::mp_size_t<1>, A&&... a ) { ::new( &t1_ ) T1( std::forward<A>(a)... ); }
@ -814,27 +814,27 @@ struct none {};
// trivially destructible, single buffered
template<class... T> struct variant_base_impl<true, true, T...>
{
int ix_;
variant_storage<none, T...> st1_;
unsigned ix_;
variant_storage<none, T...> st_;
constexpr variant_base_impl(): ix_( 0 ), st1_( mp11::mp_size_t<0>() )
constexpr variant_base_impl(): ix_( 0 ), st_( mp11::mp_size_t<0>() )
{
}
template<class I, class... A> constexpr explicit variant_base_impl( I, A&&... a ): ix_( I::value + 1 ), st1_( mp11::mp_size_t<I::value + 1>(), std::forward<A>(a)... )
template<class I, class... A> constexpr explicit variant_base_impl( I, A&&... a ): ix_( I::value + 1 ), st_( mp11::mp_size_t<I::value + 1>(), std::forward<A>(a)... )
{
}
// requires: ix_ == 0
template<class I, class... A> void _replace( I, A&&... a )
{
::new( &st1_ ) variant_storage<none, T...>( mp11::mp_size_t<I::value + 1>(), std::forward<A>(a)... );
::new( &st_ ) variant_storage<none, T...>( mp11::mp_size_t<I::value + 1>(), std::forward<A>(a)... );
ix_ = I::value + 1;
}
constexpr std::size_t index() const noexcept
{
return ix_ - 1;
return static_cast<std::size_t>( ix_ ) - 1;
}
template<std::size_t I> BOOST_CXX14_CONSTEXPR mp11::mp_at_c<variant<T...>, I>& _get_impl( mp11::mp_size_t<I> ) noexcept
@ -843,7 +843,7 @@ template<class... T> struct variant_base_impl<true, true, T...>
assert( ix_ == J );
return st1_.get( mp11::mp_size_t<J>() );
return st_.get( mp11::mp_size_t<J>() );
}
template<std::size_t I> constexpr mp11::mp_at_c<variant<T...>, I> const& _get_impl( mp11::mp_size_t<I> ) const noexcept
@ -851,14 +851,14 @@ template<class... T> struct variant_base_impl<true, true, T...>
// size_t const J = I+1;
// assert( ix_ == I+1 );
return st1_.get( mp11::mp_size_t<I+1>() );
return st_.get( mp11::mp_size_t<I+1>() );
}
template<std::size_t J, class U, class... A> BOOST_CXX14_CONSTEXPR void emplace_impl( mp11::mp_true, A&&... a )
{
static_assert( std::is_nothrow_constructible<U, A&&...>::value, "Logic error: U must be nothrow constructible from A&&..." );
st1_.emplace( mp11::mp_size_t<J>(), std::forward<A>(a)... );
st_.emplace( mp11::mp_size_t<J>(), std::forward<A>(a)... );
ix_ = J;
}
@ -868,7 +868,7 @@ template<class... T> struct variant_base_impl<true, true, T...>
U tmp( std::forward<A>(a)... );
st1_.emplace( mp11::mp_size_t<J>(), std::move(tmp) );
st_.emplace( mp11::mp_size_t<J>(), std::move(tmp) );
ix_ = J;
}
@ -884,84 +884,78 @@ template<class... T> struct variant_base_impl<true, true, T...>
// trivially destructible, double buffered
template<class... T> struct variant_base_impl<true, false, T...>
{
int ix_;
variant_storage<none, T...> st1_;
variant_storage<none, T...> st2_;
unsigned ix_;
variant_storage<none, T...> st_[ 2 ];
constexpr variant_base_impl(): ix_( 0 ), st1_( mp11::mp_size_t<0>() ), st2_( mp11::mp_size_t<0>() )
constexpr variant_base_impl(): ix_( 0 ), st_{ { mp11::mp_size_t<0>() }, { mp11::mp_size_t<0>() } }
{
}
template<class I, class... A> constexpr explicit variant_base_impl( I, A&&... a ): ix_( I::value + 1 ), st1_( mp11::mp_size_t<I::value + 1>(), std::forward<A>(a)... ), st2_( mp11::mp_size_t<0>() )
template<class I, class... A> constexpr explicit variant_base_impl( I, A&&... a ): ix_( ( I::value + 1 ) * 2 ), st_{ { mp11::mp_size_t<I::value + 1>(), std::forward<A>(a)... }, { mp11::mp_size_t<0>() } }
{
}
// requires: ix_ == 0
template<class I, class... A> void _replace( I, A&&... a )
{
::new( &st1_ ) variant_storage<none, T...>( mp11::mp_size_t<I::value + 1>(), std::forward<A>(a)... );
ix_ = I::value + 1;
::new( &st_[ 0 ] ) variant_storage<none, T...>( mp11::mp_size_t<I::value + 1>(), std::forward<A>(a)... );
ix_ = ( I::value + 1 ) * 2;
}
constexpr std::size_t index() const noexcept
{
return ix_ >= 0? ix_ - 1: -ix_ - 1;
return static_cast<std::size_t>( ix_ ) / 2 - 1;
}
template<std::size_t I> BOOST_CXX14_CONSTEXPR mp11::mp_at_c<variant<T...>, I>& _get_impl( mp11::mp_size_t<I> ) noexcept
{
assert( index() == I );
size_t const J = I+1;
assert( ix_ == J || -ix_ == J );
constexpr mp11::mp_size_t<J> j{};
return ix_ >= 0? st1_.get( j ): st2_.get( j );
return st_[ ix_ & 1 ].get( j );
}
template<std::size_t I> constexpr mp11::mp_at_c<variant<T...>, I> const& _get_impl( mp11::mp_size_t<I> ) const noexcept
{
// assert( index() == I );
// size_t const J = I+1;
// assert( ix_ == J || -ix_ == J );
// constexpr mp_size_t<J> j{};
return ix_ >= 0? st1_.get( mp11::mp_size_t<I+1>() ): st2_.get( mp11::mp_size_t<I+1>() );
return st_[ ix_ & 1 ].get( mp11::mp_size_t<I+1>() );
}
template<std::size_t I, class... A> BOOST_CXX14_CONSTEXPR void emplace( A&&... a )
{
size_t const J = I+1;
if( ix_ >= 0 )
{
st2_.emplace( mp11::mp_size_t<J>(), std::forward<A>(a)... );
ix_ = -static_cast<int>( J );
}
else
{
st1_.emplace( mp11::mp_size_t<J>(), std::forward<A>(a)... );
ix_ = J;
}
unsigned i2 = 1 - ( ix_ & 1 );
st_[ i2 ].emplace( mp11::mp_size_t<J>(), std::forward<A>(a)... );
ix_ = J * 2 + i2;
}
};
// not trivially destructible, single buffered
template<class... T> struct variant_base_impl<false, true, T...>
{
int ix_;
variant_storage<none, T...> st1_;
unsigned ix_;
variant_storage<none, T...> st_;
constexpr variant_base_impl(): ix_( 0 ), st1_( mp11::mp_size_t<0>() )
constexpr variant_base_impl(): ix_( 0 ), st_( mp11::mp_size_t<0>() )
{
}
template<class I, class... A> constexpr explicit variant_base_impl( I, A&&... a ): ix_( I::value + 1 ), st1_( mp11::mp_size_t<I::value + 1>(), std::forward<A>(a)... )
template<class I, class... A> constexpr explicit variant_base_impl( I, A&&... a ): ix_( I::value + 1 ), st_( mp11::mp_size_t<I::value + 1>(), std::forward<A>(a)... )
{
}
// requires: ix_ == 0
template<class I, class... A> void _replace( I, A&&... a )
{
::new( &st1_ ) variant_storage<none, T...>( mp11::mp_size_t<I::value + 1>(), std::forward<A>(a)... );
::new( &st_ ) variant_storage<none, T...>( mp11::mp_size_t<I::value + 1>(), std::forward<A>(a)... );
ix_ = I::value + 1;
}
@ -977,7 +971,7 @@ template<class... T> struct variant_base_impl<false, true, T...>
template<class I> void operator()( I ) const noexcept
{
using U = mp11::mp_at<mp11::mp_list<none, T...>, I>;
this_->st1_.get( I() ).~U();
this_->st_.get( I() ).~U();
}
};
@ -996,7 +990,7 @@ template<class... T> struct variant_base_impl<false, true, T...>
constexpr std::size_t index() const noexcept
{
return ix_ - 1;
return static_cast<std::size_t>( ix_ ) - 1;
}
template<std::size_t I> BOOST_CXX14_CONSTEXPR mp11::mp_at_c<variant<T...>, I>& _get_impl( mp11::mp_size_t<I> ) noexcept
@ -1005,7 +999,7 @@ template<class... T> struct variant_base_impl<false, true, T...>
assert( ix_ == J );
return st1_.get( mp11::mp_size_t<J>() );
return st_.get( mp11::mp_size_t<J>() );
}
template<std::size_t I> constexpr mp11::mp_at_c<variant<T...>, I> const& _get_impl( mp11::mp_size_t<I> ) const noexcept
@ -1013,7 +1007,7 @@ template<class... T> struct variant_base_impl<false, true, T...>
// size_t const J = I+1;
// assert( ix_ == J );
return st1_.get( mp11::mp_size_t<I+1>() );
return st_.get( mp11::mp_size_t<I+1>() );
}
template<std::size_t I, class... A> void emplace( A&&... a )
@ -1028,7 +1022,7 @@ template<class... T> struct variant_base_impl<false, true, T...>
_destroy();
st1_.emplace( mp11::mp_size_t<J>(), std::move(tmp) );
st_.emplace( mp11::mp_size_t<J>(), std::move(tmp) );
ix_ = J;
}
};
@ -1036,23 +1030,61 @@ template<class... T> struct variant_base_impl<false, true, T...>
// not trivially destructible, double buffered
template<class... T> struct variant_base_impl<false, false, T...>
{
int ix_;
variant_storage<none, T...> st1_;
variant_storage<none, T...> st2_;
unsigned ix_;
#if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER)
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63707 :-(
variant_storage<none, T...> st1_, st2_;
constexpr variant_base_impl(): ix_( 0 ), st1_( mp11::mp_size_t<0>() ), st2_( mp11::mp_size_t<0>() )
{
}
template<class I, class... A> constexpr explicit variant_base_impl( I, A&&... a ): ix_( I::value + 1 ), st1_( mp11::mp_size_t<I::value + 1>(), std::forward<A>(a)... ), st2_( mp11::mp_size_t<0>() )
template<class I, class... A> constexpr explicit variant_base_impl( I, A&&... a ): ix_( ( I::value + 1 ) * 2 ), st1_( mp11::mp_size_t<I::value + 1>(), std::forward<A>(a)... ), st2_( mp11::mp_size_t<0>() )
{
}
BOOST_CXX14_CONSTEXPR variant_storage<none, T...>& storage( unsigned i2 ) noexcept
{
return i2 == 0? st1_: st2_;
}
constexpr variant_storage<none, T...> const& storage( unsigned i2 ) const noexcept
{
return i2 == 0? st1_: st2_;
}
#else
variant_storage<none, T...> st_[ 2 ];
constexpr variant_base_impl(): ix_( 0 ), st_{ { mp11::mp_size_t<0>() }, { mp11::mp_size_t<0>() } }
{
}
template<class I, class... A> constexpr explicit variant_base_impl( I, A&&... a ): ix_( ( I::value + 1 ) * 2 ), st_{ { mp11::mp_size_t<I::value + 1>(), std::forward<A>(a)... }, { mp11::mp_size_t<0>() } }
{
}
BOOST_CXX14_CONSTEXPR variant_storage<none, T...>& storage( unsigned i2 ) noexcept
{
return st_[ i2 ];
}
constexpr variant_storage<none, T...> const& storage( unsigned i2 ) const noexcept
{
return st_[ i2 ];
}
#endif
// requires: ix_ == 0
template<class I, class... A> void _replace( I, A&&... a )
{
::new( &st1_ ) variant_storage<none, T...>( mp11::mp_size_t<I::value + 1>(), std::forward<A>(a)... );
ix_ = I::value + 1;
::new( &storage( 0 ) ) variant_storage<none, T...>( mp11::mp_size_t<I::value + 1>(), std::forward<A>(a)... );
ix_ = ( I::value + 1 ) * 2;
}
//[&]( auto I ){
@ -1063,35 +1095,18 @@ template<class... T> struct variant_base_impl<false, false, T...>
struct _destroy_L1
{
variant_base_impl * this_;
unsigned i2_;
template<class I> void operator()( I ) const noexcept
{
using U = mp11::mp_at<mp11::mp_list<none, T...>, I>;
this_->st1_.get( I() ).~U();
}
};
struct _destroy_L2
{
variant_base_impl * this_;
template<class I> void operator()( I ) const noexcept
{
using U = mp11::mp_at<mp11::mp_list<none, T...>, I>;
this_->st2_.get( I() ).~U();
this_->storage( i2_ ).get( I() ).~U();
}
};
void _destroy() noexcept
{
if( ix_ > 0 )
{
mp11::mp_with_index<1 + sizeof...(T)>( ix_, _destroy_L1{ this } );
}
else if( ix_ < 0 )
{
mp11::mp_with_index<1 + sizeof...(T)>( -ix_, _destroy_L2{ this } );
}
mp11::mp_with_index<1 + sizeof...(T)>( ix_ / 2, _destroy_L1{ this, ix_ & 1 } );
}
~variant_base_impl() noexcept
@ -1101,46 +1116,38 @@ template<class... T> struct variant_base_impl<false, false, T...>
constexpr std::size_t index() const noexcept
{
return ix_ >= 0? ix_ - 1: -ix_ - 1;
return static_cast<std::size_t>( ix_ ) / 2 - 1;
}
template<std::size_t I> BOOST_CXX14_CONSTEXPR mp11::mp_at_c<variant<T...>, I>& _get_impl( mp11::mp_size_t<I> ) noexcept
{
assert( index() == I );
size_t const J = I+1;
assert( ix_ == J || -ix_ == J );
constexpr mp11::mp_size_t<J> j{};
return ix_ >= 0? st1_.get( j ): st2_.get( j );
return storage( ix_ & 1 ).get( j );
}
template<std::size_t I> constexpr mp11::mp_at_c<variant<T...>, I> const& _get_impl( mp11::mp_size_t<I> ) const noexcept
{
// assert( index() == I );
// size_t const J = I+1;
// assert( ix_ == J || -ix_ == J );
// constexpr mp_size_t<J> j{};
return ix_ >= 0? st1_.get( mp11::mp_size_t<I+1>() ): st2_.get( mp11::mp_size_t<I+1>() );
return storage( ix_ & 1 ).get( mp11::mp_size_t<I+1>() );
}
template<std::size_t I, class... A> void emplace( A&&... a )
{
size_t const J = I+1;
if( ix_ >= 0 )
{
st2_.emplace( mp11::mp_size_t<J>(), std::forward<A>(a)... );
_destroy();
unsigned i2 = 1 - ( ix_ & 1 );
ix_ = -static_cast<int>( J );
}
else
{
st1_.emplace( mp11::mp_size_t<J>(), std::forward<A>(a)... );
_destroy();
storage( i2 ).emplace( mp11::mp_size_t<J>(), std::forward<A>(a)... );
_destroy();
ix_ = J;
}
ix_ = J * 2 + i2;
}
};
@ -2085,7 +2092,7 @@ template<class R, class F, class V1, class V2> struct visit_L2
template<class I> auto operator()( I ) const -> Vret<R, F, V1, V2>
{
auto f2 = bind_front( std::forward<F>(f), unsafe_get<I::value>( std::forward<V1>(v1) ) );
return visit<R>( f2, std::forward<V2>(v2) );
return visit<R>( f2, std::forward<V2>(v2) );
}
};