2017-02-04 2 views
7

Nach this question von ADL eine Verwendung eines Merkmals erstellen kann zu beantworten, wenn der übergebene Typ aus unserem Namespace kommt:Ist es möglich, ein Merkmal zu erstellen, um zu antworten, ob ein Typ von std kommt?

#include <utility> 

namespace helper 
{ 
    template <typename T, typename = void> 
    struct is_member_of_sample : std::false_type 
    { 
    }; 

    template <typename T> 
    struct is_member_of_sample< 
     T, 
     decltype(adl_is_member_of_sample(std::declval<T>()))> : std::true_type 
    { 
    }; 
} 

namespace sample 
{ 
    template <typename T> 
    auto adl_is_member_of_sample(T &&) -> void; 
} 

// -- Test it 

namespace sample 
{ 
    struct X; 
} 

struct Y; 

static_assert(helper::is_member_of_sample<sample::X>::value, ""); 
static_assert(not helper::is_member_of_sample<Y>::value, ""); 

int main(){} 

Aus ersichtlichen Grund dieser kann nicht auf den std Namespace angewendet werden - es gibt einfach keine Möglichkeit, das zu injizieren adl_is_member_of_sample entspricht dem Namespace std, ohne sich einem undefinierten Verhalten auszusetzen.

Gibt es eine Abhilfe ermöglicht das Merkmal zu schaffen?

+0

Das klingt wie ein [xy Problem] (http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). Warum musst du das tun? –

+0

Beachten Sie, dass ein Name für ADL-Zwecke in mehreren Namespaces enthalten sein kann. 'std :: pair ' ist in drei Namespaces - std, foo und bar. –

+1

@PeteBecker Das Problem hat Ursprung [diese Frage] (http://stackoverflow.com/questions/41867111/make-stds-data-structure-use-my-existing-non-static-hash-function-hashcode/41977680# 41977680), aber ich bin mehr gespannt, weil ich denke, es gibt viele weitere Anwendungen für sie ist ... –

Antwort

5

Dies scheint zu funktionieren:

#include <functional> 
#include <type_traits> 
#include <utility> 
#include <string> 

namespace other { struct S{}; } 

namespace my { 
    template< class Type > 
    void ref(Type&&) {} 

    template< class Type > 
    auto ref_to(Type&& o) 
     -> Type& 
    { return o; } 

    template< class Type > 
    constexpr auto is_std_type() 
     -> bool 
    { 
     using std::is_same; 
     using std::declval; 
     return not is_same< void, decltype(ref(ref_to(declval<Type>())))>::value; 
    } 

    struct Blah {}; 

    constexpr bool int_is_std  = is_std_type<int>(); 
    constexpr bool blah_is_std  = is_std_type<Blah>(); 
    constexpr bool other_is_std  = is_std_type<other::S>(); 
    constexpr bool string_is_std = is_std_type<std::string>(); 
}; 

#include <iostream> 
using namespace std; 
auto main() 
    -> int 
{ 
    cout << boolalpha; 
    cout << "int is std = " << my::int_is_std << "\n"; 
    cout << "blah is std = " << my::blah_is_std << "\n"; 
    cout << "other is std = " << my::other_is_std << "\n"; 
    cout << "string is std = " << my::string_is_std << "\n"; 
} 
+0

WOW! Ich muss es mehr analysieren, aber es sieht brilliant aus! –

+2

Nun, ich denke, es kann Ihnen falsches Positiv für einen Typ geben, der * einen Typ von 'std 'beinhaltet, abhängig davon, wie Sie" is from "definieren, aber ich habe es nicht getestet. Habe Spaß! :) –

+0

Ja. Wenn Sie 'template struct TT {};' zu 'other' hinzufügen, dann gibt es für' other :: TT '. Ich stimme immer noch mit Pete Becker überein, das klingt wie ein XY-Problem. –

Verwandte Themen