Variadic类模板

时间:2016-11-25 09:10:36

标签: c++ c++11

编译此代码时遇到问题。

我要做的就是创建一个可变参数类模板,它可以为我提供传入的所有元素的总和(例如,1,2,3,4,5,6应该给出21)是否为{{ 1}}或int。基本上,我可以递归地使用两个函数模板,我正确地得到了答案,但是当我在课堂上实现它时,它没有给我答案。

float

4 个答案:

答案 0 :(得分:3)

您的代码does not compile因为T...是无效的可变扩展,因为T不是参数包。

您的代码还有其他几个问题。我将在下面的代码段中解决它们:

template <typename T>
class Myclass
{
public:
    // `sum` needs to be initialized to a value, otherwise its value
    // will be undefined.
    T sum = 0;

    // `TRest...` is a template variadic type pack.
    template <typename... TRest>
    T func(T A, TRest... B)
    {
        sum+=A;

        // You need to return from the recursive case of `func`.
        return func(B...);
    }

    T func(T A)
    {
        sum+=A;
        return sum;
    }
};

working wandbox example

请注意,TRest...中匹配的值可以是任何类型。如果您想强制它们为T,您可以使用以下技术(或static_assert

template <typename...>
using force_to_t = T;

// ...

T func(T A, force_to_t<TRest>... B)
{
    sum+=A;

    // You need to return from the recursive case of `func`.
    return func(B...);
}

我在另一个问题上感谢to Piotr's answer了解此解决方案。

答案 1 :(得分:3)

T func(T A,T... B)
{
    sum+=A;
    func(B...);

}

func不是具有T模板参数包的函数模板时,这不是有效的C ++语法。 ...只能用于扩展包; T是类模板的非包装模板参数。

有两种方法可以做到这一点,具体取决于你想要达到的目的。

一:如果您希望func接受任意类型的混合,您可以将其设为(成员)函数模板:

template <typename T>
class Myclass
{

public:

    T sum;

    template <class F1, class... F>
    T func(F1 A, F... B)
    {
        sum+=A;
        func(B...);
        return sum;
    }

    template <class F>
    T func(F A)
    {
        sum+=A;
        return sum;
    }

};

二:如果您希望func仅接受T,您可以将其更改为使用初始化列表:

template <typename T>
class Myclass
{

public:

    T sum;

    T func(std::initializer_list<T> A)
    {
        for (const auto& a : A)
            sum+=a;
        return sum;
    }

};

请注意,这需要使用大括号中的列表调用它(例如func({1, 2, 42})而不是func(1, 2, 42),但它也是std::max采用的方法。

请注意,您的代码中存在一些与手头问题无关的问题。

我在上面的示例中修复过的一个问题是func的第一次重载并没有返回任何内容。调用它会导致未定义的行为。

评论中@Zereges指出的另一个问题是T sum未明确初始化。如果使用POD类型(例如MyClassint)实例化double,则会使用未初始化的Myclass。您应该为Myclass() : sum{} {} 添加构造函数:

<form enctype="multipart/form-data" method="post" action="upload2.php">
    Send this file: <input name="userfile" type="file" /><br />
    <input type="submit" value="Send File" />
</form>
<?php
  if (move_uploaded_file($_FILES['userfile']['tmp_name'], "C:\wamp64\www\project")) {
        print "Received {$_FILES['userfile']['name']} - its size is {$_FILES['userfile']['size']}";
    } else {
        print "Upload failed!";
    }
?>

答案 2 :(得分:1)

您可以通过将顺序sum+=A编写为std::initializer_list的初始化来避免递归调用的需要:

template <typename T>
class Myclass
{
    template <class... F>
    T func_impl(F... A)
    {
        std::initializer_list<int>{
            ((void)(sum+=A), 0)...};
        return sum;
    }
public:
    Myclass() :sum(){}
    T sum;
    template <class F1, class... F>
    T func(F1 A, F... B)
    {
        return func_impl(A, B...);
    }
};

答案 3 :(得分:0)

您可以使用另一种避免递归调用的方法来实现此目的。

template <typename T>
class Myclass
{
public:
    T sum;

    Myclass() { sum = 0; }

    template<typename ...T1>
    T func(T1 ... args)
    {
        auto l_expansion_list =
        {
            (
                [this, &args]()
                {
                    this->sum += args;
                    return true;
                }()
            )...
        };

        return sum;
    }
};