2016-04-11 59 views
1

請考慮下面的代碼片斷之間的二進制運算的結果:確定正確的尺寸類型兩個向量類型或一個向量類型以及標量型

template<class E> 
class vector_expression {}; 

template<class Tuple> 
class vector 
    : public vector_expression<vector<Tuple>> 
{ 
public: 
    using value_type = typename Tuple::value_type; 
    using size_type = typename Tuple::size_type; 
}; 

namespace detail 
{ 
    template<class E> 
    constexpr bool is_vector_expression_v = std::is_base_of_v<vector_expression<std::decay_t<E>>, std::decay_t<E>>; 

    template<class E, class = void> 
    struct value_type { using type = std::decay_t<E>; }; 
    template<class E> 
    struct value_type<E, std::enable_if_t<is_vector_expression_v<E>>> { using type = typename std::decay_t<E>::value_type; }; 

    template<class E> 
    using value_type_t = typename value_type<E>::type; 

    template<class E1, class E2, class BinaryOperation> 
    class vector_binary_operation 
    { 
    public: 
     using value_type = std::result_of_t<BinaryOperation(value_type_t<E1>, value_type_t<E2>)>; 
    }; 
} 

E1E2可能是任一類型的衍生vector_expression或用作vectorvalue_type的任何類型。

需要謹慎選擇與vector_binary_operation的結果對應的vector類型。它很有意義,它的value_type等於被調用的BinaryOperation的結果類型。

但是,正確的size_type很難推斷。這是我想做的事:

  • 如果E1E2vector_expression S,然後讓size_type = std::conditional_t< std::numeric_limits<typename std::decay_t<E1>::size_type>::max() < std::numeric_limits<typename std::decay_t<E2>::size_type>::max(), typename std::decay_t<E1>::size_type, typename std::decay_t<E2>::size_type>>>;
  • 如果E1E2(比如E1)不是vector_expression,然後讓size_type = typename std::decay_t<E2>::size_type

它將不會發生E1E2都不是vector_expression s。但是,(作爲第二個問題)我應該添加一個class = std::enable_if_t<is_vector_expression_v<E1> || is_vector_expression_v<E2>>到模板參數列表vector_binary_operation

主要問題是:如何定義size_type如上所述?

回答

2

一個辦法做到這一點是額外的特徵或充實你目前性狀:

您可以製作一個特徵,其給sizeof(E1::size_type)vector_expression0

template<class E, class = void> 
struct value_type { 
    using type = std::decay_t<E>; 
    using size_type = char; // or better some dummy type 
    static constexpr std::size_t size = 0; // To be the minimal size 
}; 
template<class E> 
struct value_type<E, std::enable_if_t<is_vector_expression_v<E>>> { 
    using type = typename std::decay_t<E>::value_type; 
    using size_type = typename std::decay_t<E>::size_type; 
    static constexpr std::size_t size = std::numeric_limits<size_type>::max(); 
}; 

然後

template<class E1, class E2, class BinaryOperation> 
class vector_binary_operation 
{ 
public: 
    using value_type = std::result_of_t<BinaryOperation(value_type_t<E1>, 
                 value_type_t<E2>)>; 
    using size_type = std::conditional_t<(value_type<E1>::size < value_type<E2>::size), 
             typename value_type <E1>::size_type, 
             typename value_type <E2>::size_type>>>; 
}; 
+0

'value_type :: size_type'聽起來有些奇怪,因爲'value_type'和'size_type'是鬆散相關的。所以,我認爲最好使用一個新的結構體'size_type',並且使用'type'和'max'成員。不過,非常感謝您的回答! – 0xbadf00d

+0

專業化中的'size'應該有'size_type'類型。[* std :: size_t可以存儲任何類型的理論上可能的對象的最大尺寸*](http://en.cppreference.com/w/cpp/types/size_t),但是這個語句與'sizeof '操作員。發生在vector中的'size_type'可能是一些抽象的複雜事物。雖然這是不尋常的,不太可能,但代碼也應該適用於這種情況。 – 0xbadf00d

+0

@ 0xbadf00d:重命名爲'vector_trait_helper',它可能在一個'struct'中都有意義,但我同意我應該改名,或者創建另一個'struct'。 – Jarod42

1

通常我發現在這種情況下,通常可以簡單地定義一組過載auto Foo(E1,E2) -> ResultType實際操作,然後設置vector_binary_operation::size_type = decltype(Foo(E1,E2))

在你的具體情況下,你會有三個重載:E1,E2或兩者都是vector_expression。

在這種特殊情況下,我看到了另一種選擇。引入幫助template<typename T> class sizer { const int max = 0; }與專業template<typename T> class sizer<vector_expression<T>> { const int max = std::numeric_limits<typename std::decay_t<E1>::size_type>::max() ; }

這背後的想法很簡單。您的一般表達式比較兩個向量表達式中的兩個屬性,並選擇該屬性最大的類型。通過將此屬性定義爲所有其他類型的零,所有其他類型的排名低於vector_typs,並且不會被選中。

+0

關於你的第一種方法:'size_type'是特別是在'vector_binary_operation'中需要用作索引操作符[]'的正確類型。我不明白我能如何推斷這種類型作爲操作「Foo」的結果類型。也許你有一個想法。 – 0xbadf00d

+0

請注意,在您的第二種方法中,我們需要使用[Jarod42](http://stackoverflow.com/a/36549065/547231)中介紹的'enable_if'解決方案,因此導致'E1'類型(通常)來自'vector_expression'。 – 0xbadf00d

+0

@ 0xbadf00d:我也沒有想法;這是你的問題領域。這個想法的核心是你有3個不同的公式來計算一個類型,這取決於輸入。通過使用函數重載,可以在三個函數聲明中使用這三個不同的公式,然後選擇合適的公式。請注意,您甚至不需要_call_函數,'decltype(Foo(...))'中的函數重載全部是從'Foo'的聲明中解析出來的。 – MSalters