检查所有可变参数的 sizeof 是否相同

Sus*_*rak 3 c++ variadic-templates

我希望能够在编译时使用 检查类的static_assert所有可变参数是否以相同的大小创建。

这是我想出的代码,但它不起作用:

template<typename... Args>
class MyClass {
    static size_t arg_reference_size;

    constexpr static bool size_is_equal() {
        return true;
    }

    template<typename First, typename... Others>
    constexpr static bool size_is_equal() {
        return arg_reference_size == sizeof(First) && size_is_equal<Others...>();
    }

    template<class First, typename... Others>
    constexpr static bool check_args_size() {
        arg_reference_size = sizeof(First);
        return size_is_equal<Others...>();
    }

    static_assert(size_is_equal<Args...>(), "");
}
Run Code Online (Sandbox Code Playgroud)

Ted*_*gmo 5

我会将类型特征移出类:

template<class T, class... R>
inline constexpr bool is_same_size_v = (... && (sizeof(T) == sizeof(R)));

template<typename... Args>
class MyClass {
    static_assert(is_same_size_v<Args...>);
};

int main() {
    MyClass<int, unsigned> x;
    //MyClass<char, long double> y; // will very likely fail
}
Run Code Online (Sandbox Code Playgroud)

如果您想将类型特征保留在类内部并基于您当前的想法,您可以确保声明size_is_equal()返回一个类型,该类型的变量设置static constexprtruefalse取决于模板参数。您不需要该函数的实际实现。返回的类型就足够了。这里std::integral_constant<bool, true>orstd::integral_constant<bool, false>将被返回 - 并且它们是带有static constexpr bool value变量的不同类型。然后您可以使用它decltype(<the returned type>)::value来获得实际结果。

template<typename... Args>
class MyClass {
    template<typename First, typename... Others>
    static auto size_is_equal() ->
        std::integral_constant<bool, (... && (sizeof(First) == sizeof(Others)))>;

    static constexpr bool size_is_equal_v =
        decltype(size_is_equal<Args...>())::value;

    static_assert(size_is_equal_v, "nope");
};
Run Code Online (Sandbox Code Playgroud)

第三种选择,如果您确实希望函数具有实现并且无法使用 C++17 折叠表达式并且需要递归:

#include <type_traits>

template <typename... Args>
class MyClass {
    template <typename... Ts>
    // SFINAE to only make this match if the param pack is empty:
    constexpr static typename std::enable_if<sizeof...(Ts) == 0, bool>::type
    size_is_equal() {
        return true;  // or `false` if an empty parameter pack should not be
                      // allowed
    }

    template <typename>  // a single parameter to terminate recursion
    constexpr static bool size_is_equal() {
        return true; // a single parameter is always true
    }

    // Take at least two template parameters and pass one of them on to the
    // recursive call:
    template <typename First, typename Second, typename... Others>
    constexpr static bool size_is_equal() {
        return sizeof(First) == sizeof(Second) &&
               size_is_equal<Second, Others...>();
    }

    static_assert(size_is_equal<Args...>(), "not equal size");
};
Run Code Online (Sandbox Code Playgroud)