mardi 22 avril 2014

pointer-to-member-function type requires an rvalue


Vote count:

0




I try to rewrite the code from the article as following (but with array of pointer-to-member-functions instead of array of pointer-to-non-member-functions):



#pragma once

#include <boost/mpl/list.hpp>

#include <memory>
#include <type_traits>

#include <cassert>

template< typename Type >
struct SizeOf
{

static constexpr decltype(sizeof(Type)) const value = sizeof(Type);

};

template< typename Type >
struct AlignOf
{

static constexpr decltype(alignof(Type)) const value = alignof(Type);

};

template< template< typename Type > class F, typename ...Types >
struct Max;

template< template< typename Type > class F, typename Last >
struct Max< F, Last >
{

using type = Last;

static constexpr decltype(F< type >::value) const value = F< type >::value;

};

template< template< typename Type > class F, typename First, typename Second, typename ...Rest >
struct Max< F, First, Second, Rest... >
{

using type = typename std::conditional< !(F< First >::value < F< Second >::value), Max< F, First, Rest... >, Max< F, Second, Rest... > >::type::type;

static constexpr decltype(F< type >::value) const value = F< type >::value;

};

template< int Base, typename Type, typename ...Types >
struct Which;

template< int Base, typename Type, typename Last >
struct Which< Base, Type, Last >
{

static constexpr int value = (std::is_same< Type, Last>::value ? Base : -1);

};

template< int Base, typename Type, typename First, typename ...Rest >
struct Which< Base, Type, First, Rest... >
{

static constexpr int value = (std::is_same< Type, First >::value ? Base : Which< 1 + Base, Type, Rest... >::value);

};

template< typename ...Types >
struct is_same;

template< typename Last >
struct is_same< Last >
{

static constexpr bool const value = true;

};

template< typename Next, typename ...Rest >
struct is_same< Next, Next, Rest... >
{

static constexpr bool const value = is_same< Next, Rest... >::value;

};

template< typename First, typename Second, typename ...Rest >
struct is_same< First, Second, Rest... >
{

static constexpr bool const value = false;

};

template< typename First, typename ...Rest >
struct variant
{

using types = typename boost::mpl::list< First, Rest... >::type;

variant()
{
construct< First >();
}

virtual
~variant()
{
apply_visitor(destroyer());
}

variant(variant const & _rhs)
{
; // TODO
}

variant(variant && _rhs)
{
; // TODO
}

template< typename Type >
variant(Type && _value)
{
construct< Type >(std::forward< Type >(_value));
}

int
which() const
{
return which_;
}

private :

using storage_type = typename std::aligned_storage< Max< SizeOf, First, Rest... >::value, Max< AlignOf, First, Rest... >::value >::type;
storage_type storage_;
int which_ = -1;

template< typename Type, typename Visitor, typename ...Args >
typename std::result_of< Visitor(Type const &, Args &&...) >::type
const_lvalue_caller(Visitor && _visitor, Args &&... _args) const &
{
return _visitor(reinterpret_cast< Type const & >(storage_), std::forward< Args >(_args)...);
}

template< typename Type, typename Visitor, typename ...Args >
typename std::result_of< Visitor(Type &, Args &&...) >::type
lvalue_caller(Visitor && _visitor, Args &&... _args) &
{
return _visitor(reinterpret_cast< Type & >(storage_), std::forward< Args >(_args)...);
}

template< typename Type, typename Visitor, typename ...Args >
typename std::result_of< Visitor(Type &&, Args &&...) >::type
rvalue_caller(Visitor && _visitor, Args &&... _args) &&
{
return _visitor(reinterpret_cast< Type && >(storage_), std::forward< Args >(_args)...);
}

template< typename Type, typename ...Args >
Type &
construct(Args &&... _args)
{
using meta = Which< 0, Type, First, Rest... >;
static_assert(!(meta::value < 0),
"the type is not listed");
which_ = meta::value;
return *new (&storage_) Type{std::forward< Args >(_args)...};
}

struct destroyer
{

template< typename Type >
void
operator () (Type & _value) const noexcept
{
_value.~Type();
}

};

public :

template< typename Visitor, typename ...Args >
auto
apply_visitor(Visitor && _visitor, Args &&... _args) const &
{
static_assert(is_same< typename std::result_of< Visitor(First const &, Args &&...) >::type, typename std::result_of< Visitor(Rest const &, Args &&...) >::type... >::value,
"non-identical return types in visitor");
using result_type = typename std::result_of< Visitor(First const &, Args &&...) >::type;
using caller_type = result_type (variant::*)(Visitor &&, Args &&...) const &;
static caller_type dispatcher_[1 + sizeof...(Rest)] =
{&variant::const_lvalue_caller< First, Visitor, Args... >, &variant::const_lvalue_caller< Rest, Visitor, Args... >...};
return (*this.*dispatcher_[which_])(std::forward< Visitor >(_visitor), std::forward< Args >(_args)...);
}

template< typename Visitor, typename ...Args >
auto
apply_visitor(Visitor && _visitor, Args &&... _args) &
{
static_assert(is_same< typename std::result_of< Visitor(First &, Args &&...) >::type, typename std::result_of< Visitor(Rest &, Args &&...) >::type... >::value,
"non-identical return types in visitor");
using result_type = typename std::result_of< Visitor(First &, Args &&...) >::type;
using caller_type = result_type (variant::*)(Visitor &&, Args &&...) &;
static caller_type dispatcher_[1 + sizeof...(Rest)] =
{&variant::lvalue_caller< First, Visitor, Args... >, &variant::lvalue_caller< Rest, Visitor, Args... >...};
return (*this.*dispatcher_[which_])(std::forward< Visitor >(_visitor), std::forward< Args >(_args)...);
}

template< typename Visitor, typename ...Args >
auto
apply_visitor(Visitor && _visitor, Args &&... _args) &&
{
static_assert(is_same< typename std::result_of< Visitor(First &&, Args &&...) >::type, typename std::result_of< Visitor(Rest &&, Args &&...) >::type... >::value,
"non-identical return types in visitor");
using result_type = typename std::result_of< Visitor(First &&, Args &&...) >::type;
using caller_type = result_type (variant::*)(Visitor &&, Args &&...) &&;
static caller_type dispatcher_[1 + sizeof...(Rest)] =
{&variant::rvalue_caller< First, Visitor, Args... >, &variant::rvalue_caller< Rest, Visitor, Args... >...};
return (*this.*dispatcher_[which_])(std::forward< Visitor >(_visitor), std::forward< Args >(_args)...);
}

template< typename Visitor, typename ...Args >
auto
apply_visitor(Visitor && _visitor, Args &&... _args) const && = delete;

};


I.e. with differentiation using ref-qualifiers for apply_visitor member-function. In such way I can write a visitors, which can steal a containing value of a variant's instance by means of rvalue-references.


All works fine, except of apply_visitor with && qualifier:



#include "variant.hpp"

#include <iostream>

#include <cstdlib>

using A = struct {};

struct printer
{

void
operator () (int x) const
{
std::cout << "int = " << x << std::endl;
}

void
//float
operator () (float x) const
{
std::cout << "float = " << x << std::endl;
//return 1.0f;
}

void
operator () (double x) const
{
std::cout << "double = " << x << std::endl;
}

void
operator () (long double x) const
{
std::cout << "long double = " << x << std::endl;
}

long
operator () (long & x, A &&)
{
std::cout << "long = " << x << std::endl;
return 0l;
}

void
operator () (unsigned && x) const
{
std::cout << "unsigned = " << x << std::endl;
}

};


int main()
{
variant< int, double > const v(1);
std::cout << v.which() << std::endl;
v.apply_visitor(printer());
variant< int, double > v1(1.1);
std::cout << v1.which() << std::endl;
v1.apply_visitor(printer());

printer const printer_;
variant< int, float, long double > const v2(222);
v2.apply_visitor(printer_);
variant< long > v4(111l);

printer vp_;
v4.apply_visitor(vp_, A());

variant< unsigned >(7u).apply_visitor(printer_); // !
return EXIT_SUCCESS;
}


The variant< unsigned >(7u).apply_visitor(printer_); line produces the following error message (g++ -std=gnu++1y version 4.8.2):



In file included from variant.cpp:1:0:
variant.hpp: In instantiation of 'auto variant<First, Rest>::apply_visitor(Visitor&&, Args&& ...) && [with Visitor = const printer&; Args = {}; First = unsigned int; Rest = {}]':
variant.cpp:71:48: required from here
variant.hpp:222:16: error: pointer-to-member-function type 'caller_type {aka void (variant<unsigned int>::*)(const printer&) &&}' requires an rvalue
return (*this.*dispatcher_[which_])(std::forward< Visitor >(_visitor), std::forward< Args >(_args)...);
^


What does it means? How to avoid such error?



asked 35 secs ago






Aucun commentaire:

Enregistrer un commentaire