Different results in Clang and GCC when casting to std::optional

前端 未结 1 871
刺人心
刺人心 2021-02-12 13:40

Given the following code:

#include 
#include 

struct foo
{
    explicit operator std::optional() {
        return std         


        
相关标签:
1条回答
  • 2021-02-12 14:04

    Since this is direct-initialization, we enumerate the constructors and just pick the best one. The relevant constructors for std::optional are :

    constexpr optional( const optional& other ); // (2)
    constexpr optional( optional&& other ) noexcept(/* see below */); // (3)
    
    template < class U = value_type >
    /* EXPLICIT */ constexpr optional( U&& value ); // (8), with U = foo&
    

    Both are viable ((8) only participates in overload resolution if int is constructible from foo& and foo is neither std::in_place_t nor std::optional<int>, all of which hold), but (8) is an exact match whereas (2) and (3) require a user-defined conversion, so it should be preferred. gcc is wrong here.

    However, gcc doesn't actually invoke (3) either. It just directly initializes my_opt from the result of converting my_foo to an optional<int>. This program with gcc 7.2 prints 3 but none of 1a, 1b, or 2:

    #include <iostream>
    
    template <class T>
    struct opt {
        opt() { }
        opt(opt const& ) { std::cout << "1a\n"; }
        opt(opt&& ) { std::cout << "1b\n"; }
    
        template <class U>
        opt(U&& ) { std::cout << "2\n"; }
    };
    
    struct foo 
    {
        explicit operator opt<int>() { std::cout << "3\n"; return {}; }
    };
    
    int main()
    {
        opt<int> o(foo{});
    }
    

    I don't think that's an allowable route. I filed 81952.

    0 讨论(0)
提交回复
热议问题