2017-02-04 2 views
7

После this question с использованием ADL можно создать признак, чтобы ответить, если передаваемая тип исходит из нашего пространства имен:Можно ли создать признак, чтобы ответить, если тип поступает из std?

#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(){} 

Из очевидных причин этого не может быть применен к std имен - там просто нет способа впрыснуть adl_is_member_of_sample эквивалентно пространству имен std, не подвергая себя неопределенному поведению.

Есть ли способ обхода, который позволяет создать признак?

+0

Это звучит как [ху проблемы] (http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). Зачем вам это нужно? –

+0

Обратите внимание, что имя может быть в нескольких пространствах имен для целей ADL. 'std :: pair ' находится в трех пространствах имен: std, foo и bar. –

+1

@PeteBecker Проблема возникла [этот вопрос] (http://stackoverflow.com/questions/41867111/make-stds-data-structure-use-my-existing-non-static-hash-function-hashcode/41977680# 41977680), но мне больше любопытно, потому что я думаю, что для этого есть еще много приложений ... –

ответ

5

Это похоже на работу:

#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! Мне нужно проанализировать это больше, но он выглядит блестящим! –

+2

Ну, я думаю, это может дать вам ложный позитив для типа, который * включает * тип из 'std', в зависимости от того, как вы определяете« от », но я не тестировал. Повеселись! :) –

+0

Да. Если вы добавите 'template struct TT {};' в 'other', тогда он даст true для' other :: TT '. Я все еще согласен с Питом Беккером, это звучит как проблема XY. –