如何使用SFINAE选择最接近的匹配类型特征?

Tre*_*key 14 c++ templates sfinae enable-if c++11

场景:
我有多种类型可以归类为序列容器.
所有序列容器都是数据结构,但并非每个数据结构都是序列容器.

以下是代码中说明的示例.此示例中涉及的唯一"重要类型"是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 */;};
Run Code Online (Sandbox Code Playgroud)

请注意,不能在Array_T上进行继承; 它必须保持其宣布的方式.


问题:
我想写两个函数.一个函数将处理所有序列容器,另一个函数将处理所有数据结构.我不知道序列容器函数是否实际存在,因为代码的那部分可能会生成也可能不会生成.

那么,我如何使用元模板编程,为类型选择最接近的匹配标识?以下是预期行为的两个示例:

情况1:

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

function(Array_T{}); // prints "sequence container"
Run Code Online (Sandbox Code Playgroud)

案例2:

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

function(Array_T{}); // prints "data structure"
Run Code Online (Sandbox Code Playgroud)

我到目前为止的尝试:

#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{});
}
Run Code Online (Sandbox Code Playgroud)

现在我意识到这不起作用,因为对于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{});
}
Run Code Online (Sandbox Code Playgroud)

那就是我被困住的地方.有没有办法在不触及Array_T减速的情况下执行此操作,并且不涉及调度的第三个功能?

Jar*_*d42 8

我会使用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());
}
Run Code Online (Sandbox Code Playgroud)