如果传入任何类型的列表,尝试禁用函数

Cur*_*ous 4 c++ sfinae template-meta-programming

我试图禁用一个函数,如果任何类型的列表类传递给该函数与以下enable_if

template <typename ContainerType, typename KeyType,
          typename = std::enable_if_t<!std::is_same<
            std::decay_t<ContainerType>,
            std::list<typename ContainerType::value_type>>::value>>
void func(ContainerType&& container, KeyType&& key)
Run Code Online (Sandbox Code Playgroud)

但是当我调用func时, vector<int>我得到了错误

candidate template ignored: substitution failure [with ContainerType = std::__1::vector<int, std::__1::allocator<int> > &, KeyType = int]: type 'std::__1::vector<int, std::__1::allocator<int> > &' cannot be used prior to '::' because it has no
  members
Run Code Online (Sandbox Code Playgroud)

向量确实有成员typedef value_type来获取存储在其中的东西的值.

知道如何解决这个问题吗?

Bar*_*rry 8

直接问题在这里:

std::list<typename ContainerType::value_type>>::value>>
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Run Code Online (Sandbox Code Playgroud)

在您的示例中,ContainerType是引用类型(std::vector<int>&),您无法从引用类型访问typedef.您必须先删除引用.

但是我们可以通过忽略该KeyType部分来简化:

template <class X> struct is_list : std::false_type { };
template <class T, class A> struct is_list<std::list<T,A>> : std::true_type { };

template <class Container, class Key,
    std::enable_if_t<!is_list<std::decay_t<Container>>::value>* = nullptr>
void func(ContainerType&&, Key&& ) { ... }
Run Code Online (Sandbox Code Playgroud)


Sto*_*ica 5

基于这篇 SO帖子我的回答.更好的方法如下:

#include <type_traits>

template<template<typename...> class TT, typename T>
struct is_instantiation_of : std::false_type { };

template<template<typename...> class TT, typename... Ts>
struct is_instantiation_of<TT, TT<Ts...>> : std::true_type { };

template <typename ContainerType, typename KeyType,
          typename = std::enable_if_t<!is_instantiation_of<
            std::list, std::decay_t<ContainerType>>::value>>
void func(ContainerType&& container, KeyType&& key)
Run Code Online (Sandbox Code Playgroud)

其主要优点是,使用其他std::list类型参数进行操作将不允许绕过您的检查.