Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/134.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 使用SFINAE可根据包装的大小实现部分专业化_C++_C++14_Template Meta Programming_Sfinae - Fatal编程技术网

C++ 使用SFINAE可根据包装的大小实现部分专业化

C++ 使用SFINAE可根据包装的大小实现部分专业化,c++,c++14,template-meta-programming,sfinae,C++,C++14,Template Meta Programming,Sfinae,我正在尝试制作一个在编译时使用字符的模板。在本例中,我想施加一个约束,即必须始终存在给定字符数的精确倍数 在没有精确匹配的情况下,我希望在包的顶部用0填充它们 (除此之外,这背后的动机是希望(在编译时,作为一个更大问题的一部分)添加对将二进制和十六进制文本映射到std::array的支持,除了填充不是字节数倍数的内容外,这工作得很好) 下面是一个简单的例子,说明我正在尝试如何让填充物发挥作用: // Thingy operates on N*4 chars - if that's not met

我正在尝试制作一个在编译时使用字符的模板。在本例中,我想施加一个约束,即必须始终存在给定字符数的精确倍数

在没有精确匹配的情况下,我希望在包的顶部用0填充它们

(除此之外,这背后的动机是希望(在编译时,作为一个更大问题的一部分)添加对将二进制和十六进制文本映射到
std::array
的支持,除了填充不是字节数倍数的内容外,这工作得很好)

下面是一个简单的例子,说明我正在尝试如何让填充物发挥作用:

// Thingy operates on N*4 chars - if that's not met use inheritance to 0 pad until it is met.
template<char ...Args>
struct thingy : thingy<0, Args...> {
    // All we do here is recursively add one more 0 via inheritance until the N*4 rule is met
};

// This specialisation does the real work, N=1 case only
template<char a, char b, char c, char d>
struct thingy<a,b,c,d> {
    enum { value = (a << 24) | (b << 16) | (c << 8) | d }; 
};

// This handles chunking the N*4 things into N cases of work. Does work along the way, only allowed for exact N*4 after padding has happened.
template <char a, char b, char c, char d, char ...Args>
struct thingy<a,b,c,d,Args...> : thingy<a,b,c,d> {
    static_assert(sizeof...(Args) % 4 == 0); // PROBLEM: this is a we're a better match than the template that pads things, how do we stop that?
    // Do something with the value we just got and/or the tail as needed
    typedef thingy<a,b,c,d> head;
    typedef thingy<Args...> tail;
};

int main() {
    thingy<1,1,1,1,1>(); // This should be equivalent to writing thingy<0,0,0,1,1,1,1,1>()
}
虽然就我所知,这是不合法的,而且在我的编译器上肯定不起作用-在我们需要查询
sizeof…(Args)
的时候,
Args
还不存在

就我所知,我们不能在包后合法添加另一个模板参数,这也失败了:

template <char a, char b, char c, char d, char ...Args, typename std::enable_if<sizeof...(Args) % 4 == 0, int>::type=0>
struct thingy<a,b,c,d,Args...> : thingy<a,b,c,d> {
    // ...
};
我也在遗产中尝试了SFINAE,但这似乎不是一个合法的地方:

template <char a, char b, char c, char d, char ...Args>
struct thingy<a,b,c,d,Args...> : std::enable_if<sizeof...(Args) % 4 == 0, thingy<a,b,c,d>>::type {
    // ...
};

就我所能理解的而言,多读一点,但这对我现在没有多大帮助


使用C++14、gcc 6.x中的内容,我如何解决这个问题?还有比完全回到绘图板更简单的选择吗?

有没有一种稍微不同的方法,使用多重继承和一个中间的helper结构来进行填充

// This handles chunking the N*4 things into N cases of work. Does work along the way, only allowed for exact N*4 after padding has happened.
template <char a, char b, char c, char d, char... Args>
struct thingy_impl : thingy_impl<a, b, c, d>, thingy_impl<Args...> {
    static_assert(sizeof...(Args) % 4 == 0);
    // Do something with the value we just got and/or the tail as needed
    typedef thingy_impl<a,b,c,d> head;
    typedef thingy_impl<Args...> tail;
};

template<char a, char b, char c, char d>
struct thingy_impl<a,b,c,d> {
    enum { value = (a << 24) | (b << 16) | (c << 8) | d }; 
};

template<int REMAINDER, char... Args>
struct padding;

template<char... Args>
struct padding<0,Args...> { using type = thingy_impl<Args...>; };

template<char... Args>
struct padding<1,Args...> { using type = thingy_impl<0,0,0,Args...>; };

template<char... Args>
struct padding<2,Args...> { using type = thingy_impl<0,0,Args...>; };

template<char... Args>
struct padding<3,Args...> { using type = thingy_impl<0,Args...>; };

template<char... Args>
struct thingy : padding<sizeof...(Args) % 4, Args...>::type { };

int main() {
    thingy<1,1,1,1,1>(); // This should be equivalent to writing thingy<0,0,0,1,1,1,1,1>()
}
//这可以处理将N*4个内容分块到N个工作案例中。这样做的过程中,只允许精确的N*4填充发生后。
模板

StgyyIyIMPL:THYYYYPIMPL/

< P>首先,C++ 17中的一个简单的解决方案,使用递归<代码>如果CONTXPRPR 帮助函数为您做填充:

template<char ... Args>
auto getThingyPadded()
{
    if constexpr (sizeof...(Args) % 4 != 0)
        return getThingyPadded<0, Args...>();
    else
        return thingy<Args...>{};
}

另一种多重继承方法(对Jarod42进行了修正和简化(谢谢!))

#包括
模板
结构t_库:公共t_库
{
typedef t_底座头;
typedef t_基尾;
};
模板
结构t_基础

{enum{value=(a我将去掉带有head/tail的列表,并使用
std::tuple
,结果是:

// No variadic here
template <char a, char b, char c, char d>
struct thingy {
    enum { value = (a << 24) | (b << 16) | (c << 8) | d }; 
};

template <typename Seq, char... Cs>
struct thingies_impl;

template <std::size_t ...Is, char... Cs>
struct thingies_impl<std::index_sequence<Is...>, Cs...>
{
private:
    static constexpr char get(std::size_t n)
    {
        constexpr char cs[] = {Cs...};
        constexpr std::size_t paddingSize = (4 - (sizeof...(Cs) % 4)) % 4;
        return (n < paddingSize) ? '\0' : cs[n - paddingSize];
    }

public:
    using type = std::tuple<thingy<get(4 * Is),
                                   get(4 * Is + 1),
                                   get(4 * Is + 2),
                                   get(4 * Is + 3)>...>;  
};

template <char... Cs>
using thingies = thingies_impl<std::make_index_sequence<(sizeof...(Cs) + 3) / 4>, Cs...>;
//这里没有变量
模板
结构物{

枚举{值=(a您可以使用一个helper函数来解决这个问题,该函数是在实际打包之前使用您希望使用的计算值调用的。让我写一个答案。您能否简化它以避免显式地分别处理1,2,3填充情况?即填充和填充就足够了。@flex:mablue:
template structpadding:padding{};
+当前对
0
的专门化。这是我采用的解决方案,它只处理
0
N
的填充情况,因为它允许我使用一些traits进一步概括填充要求,但另一种使用unpack操作符的方式我完全没有考虑到
template<bool B, class U = void>
using enableIfT = typename std::enable_if<B, U>::type;

template<std::size_t N, enableIfT<(N % 4 == 0)>* = nullptr, char ... Args>
auto getThingyPaddedHelper()
{
    return thingy<Args...>{};
}

template<std::size_t N, enableIfT<(N % 4 != 0)>* = nullptr, char ... Args>
auto getThingyPaddedHelper()
{
    return getThingyPaddedHelper<N+1, nullptr, 0, Args...>();
}

template<char ... Args>
auto getThingyPadded()
{
    return getThingyPaddedHelper<sizeof...(Args), nullptr, Args...>();
}
#include <utility>

template <char a, char b, char c, char d, char ... Args>
struct t_base : public t_base<Args...>
 {
   typedef t_base<a,b,c,d> head;
   typedef t_base<Args...> tail;
 };

template <char a, char b, char c, char d>
struct t_base<a, b, c, d>
 { enum { value = (a << 24) | (b << 16) | (c << 8) | d }; };


template <typename, typename>
struct t_helper;

template <std::size_t ... Is, char ... Cs>
struct t_helper<std::index_sequence<Is...>,
                std::integer_sequence<char, Cs...>>
   : public t_base<(Is, '0')..., Cs...>
 { };


template <char ... Cs>
struct thingy :
   public t_helper<std::make_index_sequence<(4u - sizeof...(Cs) % 4u) % 4u>,
                   std::integer_sequence<char, Cs...>>
 { };


int main ()
 {
 }
// No variadic here
template <char a, char b, char c, char d>
struct thingy {
    enum { value = (a << 24) | (b << 16) | (c << 8) | d }; 
};

template <typename Seq, char... Cs>
struct thingies_impl;

template <std::size_t ...Is, char... Cs>
struct thingies_impl<std::index_sequence<Is...>, Cs...>
{
private:
    static constexpr char get(std::size_t n)
    {
        constexpr char cs[] = {Cs...};
        constexpr std::size_t paddingSize = (4 - (sizeof...(Cs) % 4)) % 4;
        return (n < paddingSize) ? '\0' : cs[n - paddingSize];
    }

public:
    using type = std::tuple<thingy<get(4 * Is),
                                   get(4 * Is + 1),
                                   get(4 * Is + 2),
                                   get(4 * Is + 3)>...>;  
};

template <char... Cs>
using thingies = thingies_impl<std::make_index_sequence<(sizeof...(Cs) + 3) / 4>, Cs...>;