问题
The title is rather hard to formulate in word, but here is what I'm trying to achieve in non-compileable code:
template<template <typename> class Container>
Container<int> foo() {
return Container<int>{1,2,3};
}
int main() {
auto bar = foo<std::vector>();
return 0;
}
Basically I want a template function that can "compose" its return type from a type that is passed to it and a previously known type (in this case int
). In this case I want a function that returns an arbitrary data type inside a container that is specified by the caller. (By arbitrary I don't mean random or undetermined at compile time, but rather that the caller has no "input" as to what the data type will be, that is determined inside the function itself).
Is this type of thing even achievable with clang or gcc with std+1z? Am I missing something really obvious? Is there a "1 line" solution spanning hundreds of character that I don't know of?
I've seen various examples of similar things around here but they all seem to assume the functions take pointers or references as arguments and fill in those containers.
回答1:
Your only trouble here is that std::vector
is not a template <typename> class
. It is a template <typename T, typename Alloc> class
that happens to have a default argument for the second template parameter.
One way around this is using an alias template that really does take just one parameter:
#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;
}
Another approach recommended in the comments is to use a variadic typename when declaring the template of the original function, which accepts any class template taking only type arguments. And then you can instantiate it with just one argument, since the actual template has a default for the second. This works in C++11 and above.
#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;
}
回答2:
A template template parameter with typename...
template template parameter list will bind to any template name, regardless of the actual template parameter count. You can use this and speculatively assume the template to be instantiable with a single parameter.
template<template <typename...> class Container>
Container<int> foo() {
return Container<int>{1,2,3};
}
int main() {
auto bar = foo<std::vector>();
return 0;
}
This works since C++-11
as far as I know.
It would also be possible to declare a templated alias with a single parameter, making the interface more self-documenting
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;
}
来源:https://stackoverflow.com/questions/44211723/template-argument-deduction-when-the-function-returns-a-type-composed-from-the-t