Modify

Opened 2 years ago

Closed 11 months ago

#11602 closed Bugs (fixed)

boost.variant constructor accepts any type as parameter

Reported by: piotrwn1@… Owned by: Antony Polukhin
Milestone: Boost 1.62.0 Component: variant
Version: Boost 1.58.0 Severity: Problem
Keywords: Cc: raad@…

Description

There is one "converting constructor" in boost.variant which accepts any type - even those which are not convertible to instantiation types of boost.variant. This causes that writing function accepting some specific variant instantiation cause that this function is on candidate list of any type in your program.

The problem is with this constructor:

    template <typename T>
    variant(const T& operand)
    {
        convert_construct(operand, 1L);
    }

And the small code presenting the issue:

#include <iostream>
#include <boost/variant.hpp>

// types not related in any way
class A {};
class B {};
class C {};
class D {};

using ABC_variant = boost::variant<A,B,C>;

std::ostream& operator << (std::ostream& os, const ABC_variant&)
{
	return os << "ABC";
}

int main() {
	D d;
	std::cout << d;
}

As described in http://stackoverflow.com/questions/32275725/boostvariant-construction-weirdness-its-ctor-accepts-everything

compiler (gcc4.9) tries to use ostream operator with this diagnostic:

/usr/include/boost/variant/variant.hpp:1591:38: error: no matching function for call to 'boost::variant<A, B, C>::initializer::initialize(void*, D&)'

initializer::initialize(

However it should simple report that ostream operator for D is missing.

One simple way is to declare this boost.variant constructor as explicit (what probably would impact to many client code) or to make some restriction in this constructor like this C++11 way:

template <typename T, typename ...C>
struct IsAnyOf;

template <typename T, typename ...C>
struct IsAnyOf<T,T,C...> : std::true_type {};

template <typename T>
struct IsAnyOf<T> : std::false_type {};

template <typename T, typename C1, typename ...C>
struct IsAnyOf<T,C1,C...> : IsAnyOf<T, C...> {};

template <typename T, 
	  typename EnableIf = typename std::enable_if<IsAnyOf<VariantType...>::value>::type>
	variant(const T& operand)


BR, Piotr Nycz (piotrwn1 @ gmail com)

Attachments (0)

Change History (6)

comment:1 Changed 2 years ago by piotrwn1@…

Maybe better would to use IsConvertibleToAnyOf? instead of IsAnyOf?:

template <typename T, typename ...C>
struct IsConvertibleToAnyOf;

template <typename T>
struct IsConvertibleToAnyOf<T> : std::false_type {};


template <typename T, typename C1, typename ...C>
struct IsConvertibleToAnyOf<T,C1,C...> : std::integral_constant<bool,
    std::is_convertible<T,C1>::value or
    IsConvertibleToAnyOf<T,C...>::value> {};

BR,

Piotr Nycz

comment:2 Changed 18 months ago by raad@…

Cc: raad@… added

comment:3 Changed 18 months ago by raad@…

This problem also makes boost::variant unusable in C++17's std::tuple as implemented in MSVC 14 Update 2, affecting boost::signals2 (ticket #12123).

Ticket #5871 describes the same problem.

comment:4 Changed 16 months ago by Antony Polukhin

Milestone: To Be DeterminedBoost 1.62.0
Owner: changed from ebf to Antony Polukhin
Status: newassigned

comment:5 Changed 16 months ago by Antony Polukhin

Fixed in b3650685 develop, will be merged to the master branch as soon as the regression tests will cycle.

comment:6 Changed 11 months ago by Antony Polukhin

Resolution: fixed
Status: assignedclosed

Modify Ticket

Change Properties
Set your email in Preferences
Action
as closed The owner will remain Antony Polukhin.
The resolution will be deleted.

Add Comment


E-mail address and name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.