10

Đây là một đoạn mã mà tôi sẽ sử dụng để kiểm tra xem các loại mẫu variadic là duy nhất:Làm cách nào để có thể làm cho mã mẫu Phiên bản ngắn hơn này sử dụng các tính năng từ C++ 14 và C++ 1z?

template <typename...> 
struct is_one_of; 

template <typename F> 
struct is_one_of<F> { 
    static constexpr bool value = false; 
}; 

template <typename F, typename S, typename... T> 
struct is_one_of<F, S, T...> { 
    static constexpr bool value = 
     std::is_same<F, S>::value || is_one_of<F, T...>::value; 
}; 

template <typename...> 
struct is_unique; 

template <> 
struct is_unique<> { 
    static constexpr bool value = true; 
}; 

template <typename F, typename... T> 
struct is_unique<F, T...> { 
    static constexpr bool value = 
     is_unique<T...>::value && !is_one_of<F, T...>::value; 
}; 

int main() { 
    constexpr bool b = is_unique<bool, int, double>::value; 
    constexpr bool c = is_unique<int, char, int>::value; 
    static_assert(b == true && c == false, "!"); 
} 

Có cách nào để làm cho mã này ngắn hơn và/hoặc ngắn gọn hơn sử dụng các tính năng được giới thiệu trong C++ 14 và C++ 1z? Hoặc có cách nào tốt hơn để đạt được hiệu quả tương tự bằng cách sử dụng các tính năng mới không?

Trong trường hợp của C++ 1z tôi có nghĩa là: các tính năng đã có sẵn trong các phiên bản mới nhất của Clang và GCC.

+0

Không, điều đó khá súc tích như vậy. Tuy nhiên, khi biểu thức gấp được giới thiệu, bạn sẽ có thể thực hiện một số việc như: 'constexpr giá trị bool tĩnh = std :: is_same :: giá trị || ... ' –

+1

@BrianRodriguez: Điều đó cần ngoặc tròn tôi nghĩ. –

+0

Bạn có thể sử dụng một mẹo nhỏ để làm cho 'is_one_of' ngắn gọn hơn một chút: http://coliru.stacked-crooked.com/a/3b9755f28193a13b – melak47

Trả lời

6
#include <type_traits> 

template <typename F, typename... Ts> 
constexpr bool is_one_of = (std::is_same<F, Ts>{} || ...); 

template <typename...> 
constexpr bool is_unique = true; 

template <typename F, typename... Ts> 
constexpr bool is_unique<F, Ts...> = is_unique<Ts...> && !is_one_of<F, Ts...>; 

DEMO

3

Tôi muốn (bây giờ) đề nghị sử dụng gia đình std::conj/disj/nega chức năng STL:

#include <type_traits> 

template <typename H, typename... T> 
struct is_one_of : std::disjunction<std::is_same<H, T>...> {}; 

template <typename H, typename... T> 
struct is_unique : std::conjunction<std::negation<std::is_same<H, T>>..., is_unique<T...>> {}; 

template <typename H> 
struct is_unique<H> : std::true_type {}; 

int main() 
{ 
    static_assert(is_one_of<int, char, double, int, bool>::value); 
    static_assert(is_unique<int, char, double, bool>::value); 
    static_assert(!is_unique<int, int, char, double, bool>::value); 
} 

Khi fold-expressions, được thiết kế dành cho những trường hợp này, được phát hành vào ngôn ngữ này sẽ trở nên tầm thường:

namespace stx = std::experimental; 

template <typename H, typename... T> 
struct is_one_of { 
    static constexpr bool value = (stx::is_same_v<H, T> || ...); 
}; 

template <typename H, typename... T> 
struct is_unique { 
    static constexpr bool value = (!stx::is_same_v<H, T> && ... && is_unique<T...>::value); 
}; 

template <typename H> 
struct is_unique<H> : std::true_type {}; 
+0

'is_unique' của bạn chỉ kiểm tra nếu' H' là duy nhất, nhưng 'T' khác vẫn có thể có bản sao trong danh sách loại. – melak47

+1

Mã này không có cơ hội để biên dịch –

+0

Mã này bị hỏng theo nhiều cách khác nhau rõ ràng đến mức chưa bao giờ được thử nghiệm tối thiểu. –

2

Tôi phù hợp với câu trả lời của Brian Rodriguez và Piotr Scontnincki, vì nó liên quan đến phần biểu thức nếp gấp. Cho đến khi biểu thức gấp đang ở, bạn có thể thu nhỏ mã hiện một chút bằng cách loại bỏ các mẫu tiểu học không đầy đủ như sau:

template <typename...> 
struct is_one_of { 
    static constexpr bool value = false; 
}; 

template <typename F, typename S, typename... T> 
struct is_one_of<F, S, T...> { 
    static constexpr bool value = 
     std::is_same<F, S>::value || is_one_of<F, T...>::value; 
}; 

template <typename...> 
struct is_unique { 
    static constexpr bool value = true; 
}; 

template <typename F, typename... T> 
struct is_unique<F, T...> { 
    static constexpr bool value = is_unique<T...>::value && !is_one_of<F, T...>::value; 
}; 
9

Chúng tôi gần đây thêm std::disjunction vào thư mục C++ Dự thảo 1z, có thể được sử dụng cho is_one_of (và nó dừng ngay lập tức ngay khi tìm thấy kết quả phù hợp, xem liên kết để biết thêm chi tiết):

template <typename F, typename... T> 
    using is_one_of = std::disjunction<is_same<F, T>...>; 

Điều này đã được thực hiện trong thân cây GCC. Đối với phiên bản cũ của GCC bạn có thể sử dụng các chi tiết thực hiện __or_ thay vì:

template <typename F, typename... T> 
    using is_one_of = std::__or_<is_same<F, T>...>; 

Hoặc thực hiện disjunction bằng tay sử dụng C++ 11 cơ sở vật chất, như thể hiện ở phần cuối của đề nghị liên quan đến ở trên.

+0

Thật tuyệt vời !!! – 101010

Các vấn đề liên quan