// Copyright (c) 2018 Andrey Semashev
//
// Use, modification, and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

// The test verifies that Boost.Optional copy constructors do not attempt to invoke
// the element type initializing constructors from templated arguments

#include <boost/optional/optional.hpp>
#include <boost/core/enable_if.hpp>

struct no_type
{
    char data;
};

struct yes_type
{
    char data[2];
};

template< unsigned int Size >
struct size_tag {};

template< typename T, typename U >
struct is_constructible
{
    template< typename T1, typename U1 >
    static yes_type check_helper(size_tag< sizeof(static_cast< T1 >(U1())) >*);
    template< typename T1, typename U1 >
    static no_type check_helper(...);

    static const bool value = sizeof(check_helper< T, U >(0)) == sizeof(yes_type);
};

template< typename T >
class wrapper
{
public:
    wrapper() {}
    wrapper(wrapper const&) {}
    template< typename U >
    wrapper(U const&, typename boost::enable_if_c< is_constructible< T, U >::value, int >::type = 0) {}
};

inline boost::optional< wrapper< int > > foo()
{
    return boost::optional< wrapper< int > >();
}

int main()
{
    // Invokes boost::optional copy constructor. Should not invoke wrapper constructor from U.
    boost::optional< wrapper< int > > res = foo();
    return 0;
}
