1

我有一个模板:

template<typename... Ts> //T1,T2,T3,...
struct foo {
  //my struct
};

我想分别static_assert检查 T1,T3,T5,...(“奇数类型”)和 T2,T4,T6,...(“偶数类型”)。

我找到了这个简单的解决方案:

template<size_t N, typename... Ts>
struct perform_checks {};

template<size_t N, typename T, typename U, typename... Ts>
struct perform_checks<N, T, U, Ts...> : perform_checks<N, Ts...>
{
  //check for odd types
  static_assert(std::is_default_constructible<T>::value,"failure");

  //check for even types
  static_assert(std::is_copy_constructible<U>::value,"failure");
};

N参数允许它结束。我这样使用它:

template<typename... Ts>
struct foo {
  perform_checks<0,Ts...> hello;
};

这似乎工作正常。但是可以避免hello变量吗?我从不将它用于任何其他目的。

4

3 回答 3

2

您可以通过以下方式或多或少地使用enable_if1 (和 boost::mpl):

#include <boost/mpl/and.hpp>
template<size_t N, typename... Ts>
struct perform_checks {};

template<size_t N, typename T, typename U, typename... Ts>
struct perform_checks<N, T, U, Ts...> : perform_checks<N, Ts...>
{
    typedef boost::mpl::and_<std::is_default_constructible<T>::type, 
        std::is_copy_constructible<U>::type> type;
};

template < class... Ts,
       class = typename std::enable_if<perform_checks<0, Ts...>::type>
struct foo {
  //my struct
};
于 2013-06-27T22:41:40.423 回答
2

OP 中的唯一目的是foo在实例化时触发检查。这就是你需要变量的原因hello:它是foo.

我宁愿遵循<type_traits>. 更准确地说,我会perform_checks变成class(或struct)有公共static constexpt bool成员被称为valuetruefalse取决于给定类型是否通过测试。然后如果是假的,我会用一个static_assert来停止编译。value

我的解决方案假设模板类型参数的数量是偶数,如下:

#include <type_traits>

template<typename First, typename Second, typename... Others>
struct perform_checks :
    std::integral_constant<bool,
        perform_checks<First, Second>::value && // Checks First and Second
        perform_checks<Others...>::value        // Recursively "calls" itself on Others
    > {
};

// This specialization finishes the recursion and effectively performs the test
template<typename First, typename Second>
struct perform_checks<First, Second> :
    std::integral_constant<bool,
        std::is_default_constructible<First>::value && // Checks First
        std::is_copy_constructible<Second>::value      // Checks Second
    > {
};

这是一个简单的测试:

struct NonDefaultConstructible {
    NonDefaultConstructible() = delete;
};

struct NonCopyConstructible {
    NonCopyConstructible(const NonCopyConstructible&) = delete;
};

int main() {
    static_assert(perform_checks<int, double>::value, "Failure");
    static_assert(perform_checks<int, int, double, double>::value, "Failure");
    static_assert(!perform_checks<NonDefaultConstructible, int>::value, "Failure");
    static_assert(!perform_checks<int, NonCopyConstructible>::value, "Failure");
    static_assert(!perform_checks<int, int, double, NonCopyConstructible>::value, "Failure");
}

请注意,没有创建任何变量。

于 2013-06-28T09:30:14.527 回答
2

私人派生fooperform_checks<>

template <typename... Ts> struct foo : private perform_checks<Ts...> {
 // stuff
};

哦,去掉N你不需要的参数:

template <typename... Ts> struct perform_checks {};
template <typename T> struct perform_checks<T> {
  template <typename U> struct dependent_name_hack : std::false_type {};
  static_assert(dependent_name_hack<T>::value,
                "Odd number of parameters not acceptable.");
};
template <typename T, typename U, typename... Ts>
struct perform_checks<T, U, Ts...> : perform_checks<Ts...> {
  //check for odd types
  static_assert(std::is_default_constructible<T>::value,"failure");

  //check for even types
  static_assert(std::is_copy_constructible<U>::value,"failure");
};
于 2013-06-27T22:38:33.720 回答