2013-06-10 27 views
24

Làm cách nào để tạo mẫu lớp trả về xem có bất kỳ loại biến thể nào trong số các loại variadic của nó bằng loại đầu tiên hay không. Tôi muốn để có thể làm điều này:Làm thế nào để thực hiện một variadic is_same?

is_same<T, A, B, C>::value; // true if T is one of A, B or C 

Và nếu T bằng bất kỳ một trong những loại hình, tĩnh value thành viên của nó sẽ true, nếu không false. Tôi có thể làm cái này như thế nào?

+3

Kể từ khi ý định của bạn là không rõ ràng (hai người đã thực hiện cùng một cách giải thích sai) Tôi đã tự do nói một chút câu hỏi của bạn. – syam

Trả lời

30

Sử dụng mẫu đệ quy:

template<typename T, typename... Rest> 
struct is_any : std::false_type {}; 

template<typename T, typename First> 
struct is_any<T, First> : std::is_same<T, First> {}; 

template<typename T, typename First, typename... Rest> 
struct is_any<T, First, Rest...> 
    : std::integral_constant<bool, std::is_same<T, First>::value || is_any<T, Rest...>::value> 
{}; 

static_assert(is_any<int, char, double, int>::value, "error 1"); // OK 
static_assert(is_any<int, char, double, short>::value, "error 2"); // error 
+0

Cảm ơn bạn đã làm việc này. :) –

7

Điều gì đó tương tự. Đầu tiên, một thư viện lập trình meta nhỏ, bởi vì nó cho biết thêm như 2 dòng để làm điều đó quát:

template<template<typename,typename>class checker, typename... Ts> 
struct is_any_to_first : std::false_type {}; 

template<template<typename,typename>class checker, typename T0, typename T1, typename... Ts> 
struct is_any_to_first<checker, T0, T1, Ts...> : 
    std::integral_constant< bool, checker<T0, T1>::value || is_any_to_first<checker, T0, Ts...>::value> 
{}; 

Sau đó, một thực hiện 2 dòng is_any_same_to_first:

template<typename... Ts> 
using is_any_same_to_first = is_any_to_first< std::is_same, Ts... >; 

Và cho đầy đủ, bản gốc is_all, mà có thể cũng hữu ích:

template<template<typename,typename>class checker, typename... Ts> 
struct is_all : std::true_type {}; 

template<template<typename,typename>class checker, typename T0, typename T1, typename... Ts> 
struct is_all<checker, T0, T1, Ts...> : 
    std::integral_constant< bool, checker<T0, T1>::value && is_all<checker, T0, Ts...>::value> 
{}; 

template<typename... Ts> 
using is_all_same = is_all< std::is_same, Ts... >; 

Live example của is_all_same.

Lưu ý rằng việc gọi is_any_same_to_first mọi thứ ít rõ ràng hơn sẽ gây ra sự cố. 2/3 người đã cố gắng trả lời câu hỏi này, bao gồm cả tôi, giả định rằng is_same<A,B,C> là đúng iff cả ba đều cùng loại!

+0

Hmm Tôi thấy bạn đã đưa ra quyết định khác với tôi ('is_all_same' thay vì' is_any'). Sự thật được nói, tôi do dự khi hỏi OP để làm rõ về điều đó. – syam

+0

Um ... Mã này sẽ chỉ hoạt động nếu * tất cả * các loại đều giống nhau. Tôi đang tìm kiếm nếu 'T' là * hoặc là *' A', 'B', hoặc' C'. –

2

Sử dụng C++ 14 chức năng constexpr thoải mái, các loại điều là dễ dàng hơn để mã, và có lẽ nhanh hơn nhiều để biên dịch là tốt, vì vậy bạn có thể viết:

template <class T, class ... Candidates> 
constexpr bool is_all_same() { 
    bool pairs[] = {std::is_same_v<T,Candidates>...}; 
    for(bool p: pairs) if(!p) return false; 
    return true; 
} 

template <class T, class ... Candidates> 
constexpr bool is_any_same() { 
    bool pairs[] = {std::is_same_v<T,Candidates>...}; 
    for(bool p: pairs) if(p) return true; 
    return false; 
} 

Điều này được bật bởi thực tế là trong các hàm constexpr C++ 14 có thể có cho vòng lặp.

10

Nice và súc tích với C++ 17:

template <class T, class... Ts> 
struct is_any : std::disjunction<std::is_same<T, Ts>...> {}; 

Và kép:

template <class T, class... Ts> 
struct are_same : std::conjunction<std::is_same<T, Ts>...> {}; 

Một biến thể sử dụng gấp biểu:

template <class T, class... Ts> 
struct is_any : std::bool_constant<(std::is_same_v<T, Ts> || ...)> {}; 

template <class T, class... Ts> 
struct are_same : std::bool_constant<(std::is_same_v<T, Ts> && ...)> {}; 
Các vấn đề liên quan