什么是支持“部分专业化”的其他语言?

时间:2008-12-18 07:27:27

标签: language-agnostic generics programming-languages partial-specialization

部分模板专业化是C ++中通用编程最重要的概念之一。例如:实现通用交换功能:

template <typename T>
void swap(T &x, T &y) {
  const T tmp = x;
  y = x;
  x = tmp;
}

专门用于支持O(1)交换的向量:

template <typename T, class Alloc>
void swap(vector<T, Alloc> &x, vector<T, Alloc> &y) { x.swap(y); }

因此,当您在泛型函数中调用swap(x,y)时,总能获得最佳性能;

非常感谢,如果您可以在替代语言中发布等效语言(或语言部分专业化的规范示例,如果语言不支持交换概念)。

编辑:所以看起来很多回答/评论的人真的不知道什么是部分专业化,而且通用交换示例似乎妨碍了某些人的理解。更一般的例子是:

template <typename T>
void foo(T x) { generic_foo(x); }

部分专业化将是:

template <typename T>
void foo(vector<T> x) { partially_specialized_algo_for_vector(x); }

完整的专业化将是:

void foo(vector<bool> bitmap) { special_algo_for_bitmap(bitmap); }

为什么这很重要?因为你可以在泛型函数中调用foo(任何东西):

template <typename T>
void bar(T x) {
  // stuff...
  foo(x);
  // more stuff...
}

并在编译时获得最合适的实现。这是C ++实现抽象的一种方式,可以实现最小的性能损失。

希望它有助于清除“部分专业化”的概念。在某种程度上,这就是C ++如何进行类型模式匹配而不需要显式模式匹配语法(比如Ocaml / F#中的match关键字),这有时会妨碍泛型编程。

6 个答案:

答案 0 :(得分:5)

D支持部分专业化:

(扫描上述链接中的“部分”)。

特别是第二个链接将为您提供非常详细分析您可以使用模板专业化做什么,不仅在D中,还在C ++中。

以下是swap的D特定示例。它应该打印出专门用于Thing类的交换的消息。

import std.stdio;    // for writefln

// Class with swap method

class Thing(T)
{
public:

    this(T thing)
    {
        this.thing = thing;
    }

    // Implementation is the same as generic swap, but it will be called instead.
    void swap(Thing that)
    {
       const T tmp = this.thing;
       this.thing = that.thing;
       that.thing = tmp;
    }

public:

    T thing;
}


// Swap generic function

void swap(T)(ref T lhs, ref T rhs)
{
    writefln("Generic swap.");

    const T tmp = lhs;
    lhs = rhs;
    rhs = tmp;
}

void swap(T : Thing!(U))(ref T lhs, ref T rhs)
{
    writefln("Specialized swap method for Things.");

    lhs.swap(rhs);
}

// Test case

int main()
{
    auto v1 = new Thing!(int)(10);
    auto v2 = new Thing!(int)(20);

    assert (v1.thing == 10);
    assert (v2.thing == 20);
    swap(v1, v2);
    assert (v1.thing == 20);
    assert (v2.thing == 10);

    return 0;
}

答案 1 :(得分:1)

我担心C#不支持部分模板专业化。

部分模板专业化意味着:

您有一个包含两个或更多模板(泛型/类型参数)的基类。 类型参数将是&lt; T,S&gt;

在派生(专用)类中,指示其中一个类型参数的类型。 类型参数可能如下所示&lt; T,int&gt;。

因此当有人使用(实例化对象)最后一个类型参数为int的类时,将使用派生类。

答案 2 :(得分:1)

Haskell将重叠实例作为扩展名:

class Sizable a where
  size :: a -> Int

instance Collection c => Sizable c where
  size = length . toList

是一个查找任何集合大小的函数,可以有更具体的实例:

instance Sizable (Seq a) where
  size = Seq.length

另见Advanced Overlap on HaskellWiki

答案 3 :(得分:0)

实际上,您可以(不完全;见下文)使用扩展方法在C#中执行此操作:

public Count (this IEnumerable<T> seq) {
    int n = 0;
    foreach (T t in seq)
        n++;
    return n;
}

public Count (this T[] arr) {
    return arr.Length;
}

然后调用array.Count()将使用专用版本。 “不完全”是因为分辨率取决于array的静态类型,而不是运行时类型。即这将使用更通用的版本:

IEnumerable<int> array = SomethingThatReturnsAnArray();
return array.Count();

答案 4 :(得分:-1)

C#:

void Swap<T>(ref T a, ref T b) {   
  var c = a;   
  a = b;   
  b = c;
}

我猜(纯)Haskell版本将是:

swap :: a -> b -> (b,a)
swap a b = (b, a)

答案 5 :(得分:-3)

Java有泛型,允许你做类似的事情。