这个问题适用于了解Haskell(或任何其他支持高级类型的函数语言)和C++的人...
是否可以使用C++模板对更高级的kinded类型进行建模?如果是,那怎么样?
编辑:
从该演示文稿由托尼·莫里斯:
高阶多态性:
Java和C#等语言具有一阶多态性,因为它们允许我们对类型进行抽象.例如,
List<A>可以有一个reverse适用于任何元素类型(A)的函数
.
更实用的编程语言和类型系统允许我们在类型构造函数上进行抽象.
此功能称为高阶(或更高阶)多态.
示例:
伪Java,发明了高阶多态性的符号
interface Transformer<X, Y> {
Y transform(X x);
}
interface Monad<M> { // M :: * -> *
<A> M<A> pure(A a);
<A, B> M<B> bind(Transformer<A, M<B>> t, M<A> a);
}
Run Code Online (Sandbox Code Playgroud) 每个allocator类必须具有类似于以下内容的接口:
template<class T>
class allocator
{
...
template<class Other>
struct rebind { typedef allocator<Other> other; };
};
Run Code Online (Sandbox Code Playgroud)
使用分配器的类做了多余的事情:
template<class T, class Alloc = std::allocator<T> >
class vector { ... };
Run Code Online (Sandbox Code Playgroud)
但为什么这有必要呢?
换句话说,他们不能只是说:
template<class T>
class allocator { ... };
template<class T, template<class> class Alloc = std::allocator>
class vector { ... };
Run Code Online (Sandbox Code Playgroud)
哪个更优雅,更少冗余,(在某些类似的情况下)可能更安全?
他们为什么要走这rebind条路,这也会造成更多的冗余(即你要说T两次)?
(类似的问题char_traits和其他问题......尽管它们并非都有rebind,但它们仍然可以从模板模板参数中受益.)
但是,如果您需要多于1个模板参数,这将无效!
实际上,它运作得很好!
template<unsigned int PoolSize>
struct pool
{
template<class T>
struct allocator
{
T pool[PoolSize];
... …Run Code Online (Sandbox Code Playgroud) 如果我需要foo使用template-template参数定义模板函数,我通常会执行以下操作:
// Notice that the template parameter of class T is unnamed.
template <template <typename> class T> void f() { std::cout << "Yay!\n"; }
Run Code Online (Sandbox Code Playgroud)
请注意,template-template参数的template参数是未命名的,但我们可以为此参数指定一个名称:
// Now the template parameter of class T is named INNER.
template <template <typename INNER> class T> void f(const INNER &inner)
{ std::cout << inner << " Yay!\n"; }
Run Code Online (Sandbox Code Playgroud)
这似乎没有用,因为我无法INNER在函数中提供参数,上面的代码会产生以下错误:
错误:'INNER'未命名类型
令我惊讶typename INNER的typename是,在为了命名类型之后,所有关键字都没有命名类型.无论如何,这很容易修复:
// Now INNER is the name of the template parameter of class T and …Run Code Online (Sandbox Code Playgroud) 我正在尝试创建一个通用的图形结构,但我遇到了顶点和边之间的这种循环依赖关系。我像这样定义我的 Vertex 和 Edge 类:
template<typename EdgeType>
struct Vertex {
std::vector<EdgeType> successors;
};
template<typename EdgeCostType, typename VertexWrapper>
struct Edge {
EdgeCostType cost;
VertexWrapper source;
VertexWrapper dest;
};
Run Code Online (Sandbox Code Playgroud)
我想用类似的东西实例化它Vertex<Edge<int, std::shared_ptr<decltype(v)>>> v;,但我显然不能。我能做些什么来解决这种循环依赖?
编辑:
我认为这个问题归结为使用当前模板作为当前模板的模板参数之一的模板参数,例如如何做这样的事情:
template<typename VertexWrapper>
struct Vertex {
std::vector<pair<int, VertexWrapper<Vertex>>> successors;
};
Run Code Online (Sandbox Code Playgroud) 我正在尝试理解一些C++代码.我是一名经验丰富的Java程序员,正在努力学习C++.我已经阅读了一些关于模板的详尽文章,但没有人回答我以下模板规范的含义.
template<
template<template<class> class, class> class VisualOdometryTT,
template<class> class NodeBuilderTT,
class PoseGraphT>
class VORosInterface{ ... };
Run Code Online (Sandbox Code Playgroud)
我不明白的部分是template<class>我认为某些类型规范缺失的地方.但代码编译没有问题.
我正在尝试使用模板模板参数,类似于此处和此处(以及许多其他地方)所做的操作.
#include <vector>
template<template<class> class A, class B>
void f(A<B> &value) {
}
int main() {
std::vector<int> value;
f<std::vector, int>(value);
}
Run Code Online (Sandbox Code Playgroud)
但
$ g++-4.8 -std=c++0x base64.cpp
base64.cpp: In function ‘int main()’:
base64.cpp:9:23: error: no matching function for call to ‘f(std::vector<int>&)’
f<std::vector, int>(value);
^
base64.cpp:9:23: note: candidate is:
base64.cpp:4:6: note: template<template<class> class H, class S> void f(const H<S>&)
void f(H<S> &value) {
Run Code Online (Sandbox Code Playgroud)
我错过了什么?
在使用Visual Studio 2017(准确地说是15.5.6)中的Visual C ++玩耍时,我注意到__PRETTY_FUNCTION__GCC似乎起作用了!-至少在某种程度上……
但是使用编译代码会__PRETTY_FUNCTION__导致错误:
error C2065: '__PRETTY_FUNCTION__': undeclared identifier
Run Code Online (Sandbox Code Playgroud)
因此,有什么方法可以使其在Visual C ++中运行?也许包括一些?还是一些特殊的编译设置?(我认为我使用的是默认值。)为什么在所示示例中有效,但在实际使用中无效?
请注意,我不是在寻找Visual C ++替代品__PRETTY_FUNCTION__。我已经知道了 我对这里的行为感到惊讶和好奇。
我想operator<<为两者重载std::list并std::vector使用以下代码.但这两个功能几乎相同.有没有办法将它们组合起来,即创建一个更通用的重载?
#include <iterator>
#include <iostream>
#include <vector>
#include <list>
template <typename T>
std::ostream &operator<<(std::ostream &out, const std::vector<T> &v)
{
if (!v.empty())
std::copy(v.begin(), v.end(), std::ostream_iterator<T>(out, ", "));
return out;
}
template <typename T>
std::ostream &operator<<(std::ostream &out, const std::list<T> &v)
{
if (!v.empty())
std::copy(v.begin(), v.end(), std::ostream_iterator<T>(out, ", "));
return out;
}
int main()
{
std::cout << std::vector<int>({1, 2, 3, 4}) << std::endl;
std::cout << std::list<int>({1, 2, 3, 4}) << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud) 为了避免代码重复,我需要做这样的事情(在我的真实代码中,我有更复杂的类型,类似于T1和T2):
template <class T1, class T2>
struct A
{};
template <class T1, class T2>
struct B
{};
template <class X>
struct C
{
using p1 = int;
using p2 = char;
using some = X<p1, p2>;
};
int main()
{
C<A> o1; // must produce C<A<int,char> >
C<B> o2; // must produce C<B<int,char> >
}
Run Code Online (Sandbox Code Playgroud)