noexcept und ADL



  • Hallo

    Ich habe eine Klasse geschrieben, mit der ich z.B. so etwas machen kann:

    for(auto&& Element : Reversed(Vector));
    

    Der Code dafür sieht so aus:

    template< typename ContainerT >
    	class ReversedProxy {
    		ContainerT* mContainer;
    
    	public:
    		constexpr ReversedProxy( ContainerT* Container ) noexcept
    		: mContainer{ Container }
    		{
    			LIB_ASSERT( mContainer != nullptr );
    		}
    		constexpr ReversedProxy( ContainerT& Container ) noexcept
    		: ReversedProxy{ &Container }
    		{
    		}
    
    		LIB_NODISCARD auto begin()
    		{
    			using std::rbegin;
    			return rbegin( *mContainer );
    		}
    		// usw. analog für alle [c][r](begin|end)
    	};
    
    	template< typename ContainerT >
    	LIB_NODISCARD ReversedProxy< const ContainerT > Reversed( ContainerT const& Container ) noexcept
    	{
    		return { Container };
    	}
    	template< typename ContainerT >
    	LIB_NODISCARD ReversedProxy< ContainerT > Reversed( ContainerT& Container ) noexcept
    	{
    		return { Container };
    	}
    

    Nun will ich für die Iterator-Methoden wie begin() noexcept -Specifier schreiben. Was mir in die Quere kommt, ist, dass ich das ADL- using -Fallback-Idiom (hat das einen Namen?) verwende. Folglich kan ich also nicht einfach noexcept( noexcept( mContainer->rbegin() ) ) schreiben. Kann man das irgendwie lösen?

    LG



  • Mir ist gerade eine mögliche Lösung eingefallen: Dummy-Namespaces
    Hässlich, aber funktioniert. Falls jemandem etwas Besseres einfällt, immer her damit! 🙂

    #include <utility>
    #include <iostream>
    #include <iomanip>
    
    namespace foo
    {
        struct fooT{};
        void swap( fooT&, fooT& ){}
    }
    namespace bar
    {
        struct barT{};
        void swap( barT&, barT& ) noexcept {}
    }
    
    namespace sandbox
    {
        using std::swap;
    
        template< typename T >
        constexpr void swap_noexcept_detector( T const& ) noexcept( noexcept( swap( std::declval< T& >(), std::declval< T& >() ) ) )
        {
        }
    }
    using sandbox::swap_noexcept_detector;
    
    int main()
    {
        std::cout << std::boolalpha;
        std::cout << noexcept( swap_noexcept_detector( std::declval< int const& >() ) ) << '\n';
        std::cout << noexcept( swap_noexcept_detector( std::declval< foo::fooT const& >() ) ) << '\n';
        std::cout << noexcept( swap_noexcept_detector( std::declval< bar::barT const& >() ) ) << '\n';
    }
    

    Live


  • Mod

    Das kannst du auch ohne namespaces haben

    #include <utility>
    #include <iostream>
    
    struct fooT{}; void swap(fooT&, fooT&){}
    struct barT{}; void swap(barT&, barT&) noexcept {}
    
    template< typename T >
    constexpr bool swap_noexcept_detector() noexcept
    {
        using std::swap;
        return noexcept(swap(std::declval<T&>(), std::declval<T&>()));
    }
    
    int main()
    {
        std::cout << std::boolalpha;
        std::cout << swap_noexcept_detector<int>() << '\n';
        std::cout << swap_noexcept_detector<fooT>() << '\n';
        std::cout << swap_noexcept_detector<barT>() << '\n';
    }
    

    Für begin&co. ist das nicht erforderlich, diese Funktionen werden für andere Klassen ja nicht als freie Funktionen implementiert, ein direkter Aufruf von std::begin usw. ist hier angebracht.



  • Und dann einfach den Rückgabewert in den noexcept -Specifier packen? Jo, das ist auch möglich. Danke für den Vorschlag.
    Ich dachte mit der Sandbox eigentlich, dass man ReversedProxy direkt komplett da drin definieren kann und dann mit using rauszieht. Ist vielleicht ein bisschen weniger Boilerplate.

    camper schrieb:

    Für begin&co. ist das nicht erforderlich, diese Funktionen werden für andere Klassen ja nicht als freie Funktionen implementiert, ein direkter Aufruf von std::begin usw. ist hier angebracht.

    Nunja, range-based for loops finden freie begin / end auch mittels ADL, wenn die Memberfunktion nicht existiert. Daher fand ich es nicht abwegig, das für diese Klasse ebenfalls so zu implementieren.


Anmelden zum Antworten