簡體   English   中英

如何使用SFINAE選擇最接近的匹配類型特征?

[英]How do I use SFINAE to choose the closest matching type trait?

場景:
我有各種類型可以歸類為序列容器。
所有序列容器都是數據結構,但並非每個數據結構都是序列容器。

以下是代碼中說明的示例。 此示例中涉及的唯一“重要類型”是Array_T。 它分為兩類:它是一個序列容器,由於所有序列容器都是數據結構,因此它又是一個數據結構。

//A sequence container type
class Array_T{};

//A type trait for that particular sequence container
template <typename T> struct Is_Array           { static const bool value = false; };
template <>           struct Is_Array<Array_T>  { static const bool value = true;  };

//A type trait to identify all of the sequence containers
template <typename T> struct Is_A_Sequence_Container { static const bool value = Is_Array<T>::value
/* would probably "or" together more sequence types, but we only have Array_T in this example */;};

//A type trait to identify all of the data structures
template <typename T> struct Is_A_Data_Structure { static const bool value = Is_A_Sequence_Container<T>::value
/* would probably "or" together more data structure types, but we only have sequence containers in this example */;};

請注意,不能在Array_T上進行繼承; 它必須保持其宣布的方式。


問題:
我想寫兩個函數。 一個函數將處理所有序列容器,另一個函數將處理所有數據結構。 我不知道序列容器函數是否實際存在,因為代碼的那部分可能會生成也可能不會生成。

那么,我如何使用元模板編程,為類型選擇最接近的匹配標識? 以下是預期行為的兩個示例:

情況1:

// ...
//Both functions exist! Call the more specific one.
// ...

function(Array_T{}); // prints "sequence container"

案例2:

// ...
//Only the data structure one exists(not the sequence container one)
// ...

function(Array_T{}); // prints "data structure"

我到目前為止的嘗試:

#include <iostream>
#include <type_traits>

//A sequence container type
class Array_T{};

//A type trait for that particular sequence container
template <typename T> struct Is_Array           { static const bool value = false; };
template <>           struct Is_Array<Array_T>  { static const bool value = true;  };

//A type trait to identify all of the sequence containers
template <typename T> struct Is_A_Sequence_Container { static const bool value = Is_Array<T>::value
/* would probably "or" together more sequence types, but we only have Array_T in this example */;};

//A type trait to identify all of the data structures
template <typename T> struct Is_A_Data_Structure { static const bool value = Is_A_Sequence_Container<T>::value
/* would probably "or" together more data structure types, but we only have sequence containers in this example */;};

// ↑ all of this code was already shown to you


//NOTE: This function MAY OR MAY NOT actually appear in the source code
//This function handles all sequence types
template<class T, typename std::enable_if<Is_A_Sequence_Container<T>::value,int>::type=0>
void function(T t) {
    std::cout << "sequence container" << std::endl;
    return;
}

//This function handles all data structures; assuming a more specific function does not exist(*cough* the one above it)
template<class T, typename std::enable_if<Is_A_Data_Structure<T>::value,int>::type=0>
void function(T t) {
    std::cout << "data structure" << std::endl;
    return;
}

int main(){

    function(Array_T{});
}

現在我意識到這不起作用,因為對於enable_ifs的兩個值都是真的。
所以我想在數據結構函數中添加第二個enable_if來檢查序列容器函數是否存在。 像這樣的東西:

//...
//This function handles all data structures; assuming a more specific function does not exist(*cough* the one above it)
template<class T, typename std::enable_if<Is_A_Data_Structure<T>::value,int>::type=0,
                  typename std::enable_if</*if the more specific function does not exist*/,int>::type=0>>
void function(T t) {
    std::cout << "data structure" << std::endl;
    return;
}

int main(){

    function(Array_T{});
}

那就是我被困住的地方。 有沒有辦法在不觸及Array_T減速的情況下執行此操作,並且不涉及調度的第三個功能?

我會使用Tag調度:

struct DataStructureTag {};
struct SequenceContainerTag : public DataStructureTag {};

template <typename T> struct DataStructureTagDispatcher
{
    typedef typename std::conditional<Is_A_Sequence_Container<T>::value,
                                      SequenceContainerTag,
                                      DataStructureTag>::type type;
};


// NOTE: This function MAY OR MAY NOT actually appear in the source code
// This function handles all sequence types
template<class T>
void function(T&& t, const SequenceContainerTag&) {
    std::cout << "sequence container" << std::endl;
    return;
}

// This function handles all data structures (not handled my a more specific function)
template<class T>
void function(T&& t, const DataStructureTag&) {
    std::cout << "data structure" << std::endl;
    return;
}

template <class T>
typename std::enable_if<Is_A_Data_Structure<T>::value, void>::type
function(T&& t)
{
    typedef typename DataStructureTagDispatcher<T>::type tag;
    function(t, tag());
}

您還可以使用類層次結構來消除歧義的歧義

struct R2 {};
struct R1 : R2 {};

//NOTE: This function MAY OR MAY NOT actually appear in the source code
//This function handles all sequence types
template<class T, typename std::enable_if<Is_A_Sequence_Container<T>::value,int>::type=0>
void function(R1, T t) {
    std::cout << "sequence container" << std::endl;
    return;
}

//This function handles all data structures; assuming a more specific function does not exist(*cough* the one above it)
template<class T, typename std::enable_if<Is_A_Data_Structure<T>::value,int>::type=0>
void function(R2, T t) {
    std::cout << "data structure" << std::endl;
    return;
}

int main(){
    function(R1{}, Array_T{});
}

我改編了https://stackoverflow.com/a/264088/2684539

// template funcName should exist
#define HAS_TEMPLATED_FUNC(traitsName, funcName, Prototype)                          \
    template<typename U>                                                             \
    class traitsName                                                                 \
    {                                                                                \
        typedef std::uint8_t yes;                                                    \
        typedef std::uint16_t no;                                                    \
        template <typename T, T> struct type_check;                                  \
        template <typename T = U> static yes &chk(type_check<Prototype, &funcName>*); \
        template <typename > static no &chk(...);                                    \
    public:                                                                          \
        static bool const value = sizeof(chk<U>(0)) == sizeof(yes);                  \
    }

接着

//NOTE: This function MAY OR MAY NOT actually appear in the source code
//This function handles all sequence types
template<class T, typename std::enable_if<Is_A_Sequence_Container<T>::value,int>::type = 0>
void function(T t) {
    std::cout << "sequence container" << std::endl;
    return;
}

// this assumes that any template 'function' exists
// (Do you have version for `data structure` ?)
// or else create a dummy struct and then
// template <T>
// typename std::enable_if<std::is_same<T, dummy>::value>::type function(dummy) {}
HAS_TEMPLATED_FUNC(isFunctionExist_Specialized, function<T>, void (*)(T));

// This function handles all data structures not already handled
template<class T, typename std::enable_if<Is_A_Data_Structure<T>::value, int>::type = 0,
                  typename std::enable_if<!isFunctionExist_Specialized<T>::value, int>::type = 0>
void function(T t) {
    std::cout << "data structure" << std::endl;
    return;
}
// Care, isFunctionExist_Specialized<T>:: value is computed only once,
// so you have to use another
// `HAS_TEMPLATED_FUNC(isFunctionExist, function<T>, void (*)(T));`
// to take into account these new functions.

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM