【问题标题】:Template argument deduction when the function returns a type composed from the template type and another当函数返回由模板类型和另一个组成的类型时的模板参数推导
【发布时间】:2017-10-27 22:43:15
【问题描述】:

标题很难用文字表达,但这是我试图在不可编译的代码中实现的目标:

template<template <typename> class Container>
Container<int> foo() {
    return Container<int>{1,2,3};
}

int main() {
    auto bar = foo<std::vector>();
    return 0;
}

基本上,我想要一个模板函数,它可以从传递给它的类型和先前已知的类型(在本例中为 int)“组合”其返回类型。在这种情况下,我想要一个在调用者指定的容器内返回任意数据类型的函数。 (任意我不是指在编译时随机或不确定,而是调用者没有关于数据类型的“输入”,这是在函数本身内部确定的)。

这种类型的事情甚至可以用clang或gcc和std+1z来实现吗?我错过了一些非常明显的东西吗?有没有我不知道的跨越数百个字符的“1 行”解决方案?

我在这里看到过各种类似的例子,但它们似乎都假设函数将指针或引用作为参数并填充这些容器。

【问题讨论】:

  • 我不知道这是否是您的解决方案,但如果您将函数的模板参数设为template&lt;template &lt;typename...&gt; class Container&gt;,它就会编译。
  • @ James Root 我不知道可变参数模板的黑魔法是什么,但是我已经苦苦挣扎了将近半个小时的更复杂的函数现在刚刚编译并通过了所有单元测试。所以,如果你能把它写下来作为答案......(虽然我想知道它实际发生的原因,但现在我很高兴它终于奏效了:p)
  • @JamesRoot 这比我的解决方案好,虽然我有点惊讶它的工作原理。
  • @James Root,我也不确定你的第一个问题是什么意思......大概它看起来像 {new int(1), new int(2) ... etc}
  • 代码按with gcc 工作。根据doc 的说法,默认情况下clang 有意禁用此功能,但可以通过-frelaxed-template-template-args 启用。

标签: c++ templates metaprogramming template-meta-programming c++17


【解决方案1】:

您唯一的问题是std::vector 不是 template &lt;typename&gt; class。它是一个template &lt;typename T, typename Alloc&gt; class,恰好有第二个模板参数的默认参数。

解决这个问题的一种方法是使用一个别名模板,它确实只需要一个参数:

#include <vector>

template<template <typename> class Container>
Container<int> foo() {
    return Container<int>{1,2,3};
}

template <typename T>
using Vec = std::vector<T>;

int main() {
    auto bar = foo<Vec>();
    return 0;
}

cmets 中推荐的另一种方法是在声明原始函数的模板时使用可变类型名,该模板接受任何只接受类型参数的类模板。然后你可以只用一个参数来实例化它,因为实际的模板有第二个的默认值。这适用于 C++11 及更高版本。

#include <vector>

template<template <typename...> class Container>
Container<int> foo() {
    return Container<int>{1,2,3};
}

int main() {
    auto bar = foo<std::vector>();
    return 0;
}

【讨论】:

  • 啊,这就是我正在寻找的解释 ^^... 我没有意识到 std 容器实际上有第二个推导出的模板参数,我实际上并没有考虑查看标题矢量的....
  • James Root 的解决方案似乎更优雅,所以我想说也许你应该在答案中包含它以使其完整......也就是说,如果你认为这个问题可能会出现任何人的搜索引擎,标题都不是最好的,问题有点小众
【解决方案2】:

带有typename... 模板模板参数列表的模板模板参数将绑定到任何模板名称,而不管实际的模板参数计数.您可以使用它并推测性地假设模板可以使用单个参数进行实例化。

template<template <typename...> class Container>
Container<int> foo() {
    return Container<int>{1,2,3};
}

int main() {
    auto bar = foo<std::vector>();
    return 0;
}

据我所知,这从C++-11 开始有效。


还可以使用单个参数声明模板化别名,使界面更加自文档化

template<template <typename> class Container>
Container<int> foo() {
    return Container<int>{1,2,3};
}

template<typename T> using vector_container = std::vector<T>;
int main() {
    auto bar = foo<vector_container>();
    return 0;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-15
    相关资源
    最近更新 更多