2

我正在尝试静态检查可变参数模板参数列表中是否存在类型。但是,此模板列表实际上存在于传递单一类型的类中。此处的答案显示了如何检查参数列表或参数包,但我不确定如何测试包含可变参数模板的类。

例如

template <typename ...S>
class Services {};

template <typename Services>
class ServiceLocator
{
public:
      template <typename T>
      T& Resolve() 
      { 
           static_assert( check_t_exists_in_variadic_template_within_Services );
           return Find<T>();  
      }

};

我可以在这个 static_assert 中写什么来确保检查对这个服务定位器的每个调用,并且如果使用服务内的模板参数列表中不存在的类型调用 Resolve,则会引发编译器错误?

我特别关注的是:

static_assert(is_any<T,Services::S...>::value, "T does not exist in Services::S");
4

3 回答 3

2

当前代码的一个问题是 ServiceLocator 采用具体类型,因此您丢失了传递给服务的模板参数。要检索它们,您需要以某种方式对其进行 typedef ,因此我选择了 std::tuple ,因为您不能直接对可变参数列表进行 typedef 。

#include <tuple>
#include <type_traits>

template <typename Type, typename Collection>
struct contains;

template <typename Type>
struct contains<Type, std::tuple<>>
{
    typedef std::false_type result;
};

template <typename Type, typename ... Others>
struct contains<Type, std::tuple<Type, Others...>>
{
    typedef std::true_type result;
};

template <typename Type, typename First, typename ... Others>
struct contains<Type, std::tuple<First, Others...>>
{
    typedef typename contains<Type, std::tuple<Others...>>::result result;
};

template <typename ... S>
struct Services
{
    typedef std::tuple<S...> Collection;
};

template <typename ServicesType>
class ServiceLocator
{
public:
    template <typename T>
    T * Resolve()
    {
        static_assert(contains<T, typename ServicesType::Collection>::result::value, "Fail");
        return nullptr;
    }
};

class S1 {};
class S2 {};
class S3 {};

int main(int /*argc*/, char * /*argv*/[])
{
    Services< S1, S2 > services;
    ServiceLocator< decltype(services) > locator;

    locator.Resolve< S1 >();
    locator.Resolve< S2 >();
    locator.Resolve< S3 >(); // triggers static_assert

    return 0;
}

我只用clang检查过,但我希望这会有所帮助。

于 2013-10-18T19:44:27.503 回答
2

根据François 的回答,这是一个较短的版本,它避免使用std::tuple和使用std::integral_constant(via true/false_type),并提供 C++14 样式的contains_v别名。不过总体思路是一样的。

template <typename T, typename... Args>
struct contains;

template <typename T>
struct contains<T> : std::false_type {};

template <typename T, typename... Args>
struct contains<T, T, Args...> : std::true_type {};

template <typename T, typename A, typename... Args>
struct contains<T, A, Args...> : contains<T, Args...> {};

template <typename T, typename... Args>
constexpr bool contains_v = contains<T, Args...>::value;

你可以像这样使用它:

static_assert(contains_v<float, float, double>,
    "failure: float not among <float, double>"); // does not trigger

static_assert(contains_v<int, float, double>,
    "failure: int not among <float, double>"); // triggers
于 2016-09-02T14:16:39.850 回答
0

这是一种使用方法constexpr

#include <type_traits>

template <typename T>
constexpr bool contains() {
    return false;
}

template <typename T, typename A, typename... Tail>
constexpr bool contains() {
    return std::is_same<T, A>::value ? true : contains<T, Tail...>();
}

int main()
{
    static_assert(contains<float, int, double, float>(), "does contain float");
    static_assert(contains<float, int, double, char>(), "does not contain float");
}

除了更简单、更容易理解 (IMO) 之外,此方法还具有易于扩展到其他需求的优点,因为您可以将std::is_same调用替换为任何其他constexpr bool表达式,例如std::is_base_of为了检查参数包是否包含任何基础或派生类型。

于 2020-08-13T03:48:47.023 回答