c++ - 将包含 initializer_list 的参数包扩展到构造函数

标签 c++ c++11 variadic-functions initializer-list variadic-templates

我打算使用 shared_ptr在即将到来的项目中相当多,所以(不知道 std::make_shared )我想写一个可变参数模板函数 spnew<T>(...)作为shared_ptr -返回new的替身.一切都很顺利,直到我尝试使用其构造函数包含 initializer_list 的类型。 .当我尝试编译下面的最小示例时,我从 GCC 4.5.2 得到以下信息:

In function 'int main(int, char**)':
too many arguments to function 'std::shared_ptr spnew(Args ...) [with T = Example, Args = {}]'

In function 'std::shared_ptr spnew(Args ...) [with T = Example, Args = {}]':
no matching function for call to 'Example::Example()'

Oddly enough, I get equivalent errors if I substitute std::make_shared for spnew. In either case, it seems to be incorrectly deducing the parameters when an initializer_list is involved, erroneously treating Args... as empty. Here's the example:

#include <memory>
#include <string>
#include <vector>

struct Example {

    // This constructor plays nice.
    Example(const char* t, const char* c) :
        title(t), contents(1, c) {}

    // This one does not.
    Example(const char* t, std::initializer_list<const char*> c) :
        title(t), contents(c.begin(), c.end()) {}

    std::string title;
    std::vector<std::string> contents;

};

// This ought to be trivial.
template<class T, class... Args>
std::shared_ptr<T> spnew(Args... args) {
    return std::shared_ptr<T>(new T(args...));
}

// And here are the test cases, which don't interfere with one another.
int main(int argc, char** argv) {
    auto succeeds = spnew<Example>("foo", "bar");
    auto fails = spnew<Example>("foo", {"bar"});
}

这只是我的疏忽还是错误?

最佳答案

你可以这样做 -

#include <memory>
#include <string>
#include <iostream>
#include <vector>

struct Example {

    template<class... Args>
    Example(const char* t, Args... tail) : title(t) 
    {
        Build(tail...);
    }

    template<class T, class... Args>
    void Build(T head, Args... tail) 
    { 
        contents.push_back(std::string(head)); 
        Build(tail...);
    }

    template<class T>
    void Build(T head)
    { 
        contents.push_back(std::string(head)); 
    }

    void Build() {}        

    std::string title;
    std::vector<std::string> contents;

};

template<class T, class... Args>
std::shared_ptr<T> spnew(Args... args) {
    return std::shared_ptr<T>(new T(args...));
}

int main(int argc, char** argv) {
    auto succeeds = spnew<Example>("foo", "bar");
    auto fails = spnew<Example>("foo", "bar", "poo", "doo");

    std::cout << "succeeds->contents contains..." << std::endl;
    for ( auto s : succeeds->contents ) std::cout << s << std::endl;

    std::cout << std::endl << "fails->contents contains..." << std::endl;
    for ( auto s : fails->contents ) std::cout << s << std::endl;
}

尽管通用模板是类型安全的,因为编译器会提示 contents.push_back 如果传递的类型不可转换为 const char *

如上所述,您的代码在 gcc 4.6 上运行良好,但是您收到的警告在此处进行了解释 why-doesnt-my-template-accept-an-initializer-list , 并且可能不是标准 兼容,尽管 c++0x 标准尚未发布,因此这可能会改变。

关于c++ - 将包含 initializer_list 的参数包扩展到构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5798608/

相关文章:

c++ - 这种获取模板参数包中最后一个元素的方法是否有隐藏的开销?

c++ - 不同参数类型的可变参数模板函数的递归

c++ - void main的由来是什么?

c# - 获取手指在触摸板上的位置

C++:cout 和函数调用之间的求值顺序

java - Java 编译器如何区分这两个构造函数/方法?

c++ - 如果用户选择是,则执行 while 循环以重新启动程序,但行为不正确

c++ - 在有向图中复制多态对象的构造函数

c++ - 为什么 C++ Allocator 概念具有构造和销毁功能?

c++ - 什么逻辑与操作与流输出有关?