如何使c++模板化函数与返回类型无关,以便将来专门化
How to make a C++ templated function agnostic to the return type for future specialization
我想有一个通用的模板函数声明,我不知道(已经)返回类型,类似于:
**template <class T> auto getIds() noexcept -> std::vector<Any>;**
然后可以用几个输入类型和一个基于它的返回类型对函数进行专门化:
template <> auto getIds<MyClass>() noexcept -> std::vector<decltype(MyClass::id)>
{
// implementation here.
}
最后调用它而不设置返回值:
auto val = getIds<MyClass>();
这可能吗?如何?
指出:
我想避免的是必须在调用函数中手动设置Id类型:
auto val = getIds<MyClass, decltype(MyClass::id)>(); // Ugly
我也抛弃了任何(非基于模板的)解决方案,比如从RootMyClass扩展所有类型。不是这些解决方案不好,而是它们没有抓住问题的关键。
试着更清楚一点:
如果我写
class MyClass { public: int id1=4;};
template <class T, class Id> auto getIds() -> Id;
template <> auto getIds<MyClass, decltype(MyClass::id1)>() -> decltype(MyClass::id1)
{
return 1;
}
auto main() -> int
{
getIds<MyClass>(); // Do not compile
getIds<MyClass, decltype(MyClass::id1)>(); // Compile but ugly
}
我希望返回类型是隐式的,但是我没有找到通过专门化实现这一点的方法:
template <class T> getIds() noexcept -> WHICH TYPE?;
不幸的是,您不能在专门化中更改返回类型。你能做的就是在不同的重载中改变返回类型。很明显。此外,函数模板特化要比函数重载复杂得多,所以我们就这样做吧。
引入一个空的类型包装器,如:
template <typename T> struct wrapper { };
并将默认实现转发给它(我假设这里是c++ 14,否则您可以将其包装在decltype()
中,并在末尾返回):
template <typename T>
auto getIds() { return getIds(wrapper<T>{}); }
将泛型版本声明为:
template <typename T>
void getIds(wrapper<T> );
不要定义它。然后,每当有人试图做:
auto ids = getIds<X>();
如果没有重载,编译失败,因为不能从void
赋值。然后,您可以在您认为合适的时候重载:
std::vector<decltype(MyClass::id)> getIds(wrapper<MyClass> )
{ ... }
最后一个例子:
#include <iostream>
#include <vector>
template <typename T> struct wrapper { };
template <typename T>
auto getIds() -> decltype(getIds(wrapper<T>{}))
{
return getIds(wrapper<T>{});
}
template <typename T>
void getIds(wrapper<T> ) { }
struct MyClass {
int id;
};
std::vector<decltype(MyClass::id)> getIds(wrapper<MyClass> )
{
return {1, 2, 3};
}
int main()
{
for (auto id : getIds<MyClass>()) {
std::cout << id << " ";
}
}
这实际上非常类似于Haskell类型类,并且令人惊讶地工作。在实际使用中,我会使用函数来允许部分专门化。
#include <iostream>
template<typename T>
decltype(T::x) getX(T const& t) { return; }
class A { public: int x; A(int x):x(x){} };
template<> int getX<A>(A const& a) {
return a.x;
}
class B { public: std::string x; B(std::string x):x(std::move(x)){} };
template<> std::string getX<B>(B const& b) {
return b.x;
}
int main() {
A a(42);
B b("43");
std::cout << getX(a) << std::endl;
std::cout << getX(b) << std::endl;
}
可以看到,每个专门化都必须(可以?)显式地提供返回类型。如果您愿意,可以使用decltype(A::x)
(和B::x)
分别)。
为了使它更像haskell,您可以期望在类型本身(基本上是一个类型族)中有一个类型标记:
template<typename T>
typename T::TypeOfX getX(T const& t) { return; }
,因此:
class A {
using TypeOfX = int;
TypeOfX someComplexLogicToGetX();
};
为实际类型实例化类型的两种解决方案,除了一种从字段的类型获取,另一种从直接的"类型变量"获取。
相关文章:
- 是否可以对零模板参数进行模板专门化
- 尝试根据类中 typedef 的存在来专门化模板函数
- 如何基于模板化类的基类专门化成员函数
- 使用 std::async 时死锁,将来作为成员
- 如何为指向复杂值的迭代器专门化算法?
- 专门化模板覆盖函数/避免对象切片
- 我能否根据其运算符()的签名专门化可变参数模板参数
- SDL_ttf清除我之前和将来的所有渲染
- 如何使用模板化类专门化模板化函数?
- 线程 std::调用未知类型,无法专门化函数错误
- 输入两个不专门化大小的矩阵
- 如何在模板类中专门化赋值运算符?
- 如何专门化容器和枚举的模板
- Clang拒绝类模板的嵌套类仅通过专门化定义的代码是正确的吗
- 取消专门化C++模板参数
- SFINAE的变分变量模板专门化
- 如何在编译时专门化大型模板函数中的小部分
- 如何在c++运算符()中专门化调用模板
- 模板函数,其中一个参数需要专门化,而另一个不需要
- 如何使c++模板化函数与返回类型无关,以便将来专门化