在编译时间检查模板参数类型是否设置或多键,并且容器的元素类型是算术的

Check at compile time if a template argument type is set or multiset, and element type of the container is arithmetic

本文关键字:类型 元素 检查 时间 编译 参数 设置 是否      更新时间:2023-10-16

i具有一个名为'quare'接受2个参数的函数,每个函数应为std :: set ::或std :: multiSet,并且容器的元素类型应为算术类型(int,float,double ...)。如果不满足2个条件,我希望编译器报告错误。

我希望我的代码可以这样运行:

int main(void)
{
    std::set<int> s1;
    std::set<int> s2;
    equal(s1, s2);    //  OK
    std::multiset<float> s3;
    std::multiset<float> s4;
    equal(s3, s4);    //  OK
    std::set<int> s5;
    std::multiset<int> s6;
    equal(s5, s6);    //  compile error
    std::set<int*> s7;
    std::set<int*> s8;
    equal(s7, s8);    //  compile error
    std::vector<int> s9;
    std::vector<int> s10;
    equal(s9, s10);    //  compile error
    return 0;
}

现在可以检查元素是否为算术类型,如下:

template <class Container, class = typename std::enable_if<std::is_arithmetic<typename Container::value_type>::value>::type>
bool equal(const Container &container1, const Container &container2)
{
    return true;
}

但是如何确保仅设置容器或多键?

编译器可以支持C 11,例如VC2015或GCC4.8

创建一个is_set_or_multiset类型特征,该特质将使用模板专业匹配std::set<...>std::multiset<...>

template <typename>
struct is_set_or_multiset : std::false_type {};
template <typename... Ts>
struct is_set_or_multiset<std::set<Ts...>> : std::true_type {};
template <typename... Ts>
struct is_set_or_multiset<std::multiset<Ts...>> : std::true_type {};

然后将其用作enable_if子句中的附加条件:

template <class Container, 
          class = typename std::enable_if<
                                std::is_arithmetic<typename Container::value_type>::value
                             && is_set_or_multiset<Container>{}
                                >::type>
bool equal(const Container &container1, const Container &container2)
{
    return true;
}

wandbox上的实时示例

template<template<class...>class Z, class T>
struct is_instance_of_template : std::false_type {};
template<template<class...>class Z, class...Ts>
struct is_instance_of_template<Z,Z<Ts...>> : std::true_type {};
template<class Container>
using value_type_t = typename Container::value_type;
template <class Container,
    std::enable_if_t<
        std::is_arithmetic<value_type_t<Container>>{}
        && (
            is_instance_of_template<std::set, Container>{}
            || is_instance_of_template<std::multiset, Container>{}
        )
    >* =nullptr
>
bool equal(const Container &container1, const Container &container2)
{
  static_assert( std::is_arithmetic<value_type_t<Container>>{},
    "Container must contain arithmetic values"
  );
  static_assert(
    is_instance_of_template< std::set, Container >{}
    || is_instance_of_template< std::multiset, Container >{},
    "Container must be a set or multiset"
  );
  return true;
}

static_assert S只是为了验证其上方的Sfinae。如果您不需要Sfinae,则可以跳过Sfinae - 如果您可以使用硬构建休息而不是无法匹配此过载。

请注意,根据我的经验,enable_if_t<>* =nullptr技术在某些编译器(例如MSVC2015)上无法完美地工作。在这些编译器上,使用class=enable_if_t<>。我使用enable_if_t<>* =nullptr,因为它摆脱了"相同的模板签名"问题。