【问题标题】:statically typed language with traits and function overloading?具有特征和函数重载的静态类型语言?
【发布时间】:2013-07-26 00:32:39
【问题描述】:

是否存在任何种语言:

  • 是静态(强)类型的
  • 支持泛型(模板)
  • 支持特征/多重继承/接口委托
  • 允许函数重载(也允许继承成员)

基本上,在伪代码中,我想要这个:

class Template<SomeType> { void function(SomeType i) {} }
class Composed extends Template<int>, Template<double> { };
Composed composed;
composed.function(3); //calls function(int)
composed.function(2.5); //calls function(double)

从 wiki 列表 http://en.wikipedia.org/wiki/Multiple_inheritance#Implementations 我尝试用以下编程语言编写代码(我还包括最新的尚未发布的 1.0 版(2013 年)语言,如 Kotlin、锡兰):

  • C++ 几乎可以,但无法解析 composed 变量的重载函数
  • Scala 编译错误:trait 继承了两次;即使被间接继承欺骗,它仍然会产生错误;另见other guy's question about multiple generic mixin inheritance in Scala
  • 埃菲尔编译错误:没有函数重载
  • Ceylon trait 不能有变量(并且没有受保护的成员,因此在派生类中存储数据没有技巧,Ceylon 中的特征是无用的)
  • Fantom 没有泛型/模板
  • Kotlin 编译错误:超类型出现两次;委托看起来很独特,但它没有用,因为既不能访问受保护的成员,也不能访问委托给的变量
  • Rust 没有函数重载; trait 不能存储数据;特征不能有定义的方法(带有主体) - 正在处理的问题;
  • OCaml 编译错误:没有函数重载;它也没有检查我的函数的参数类型,那么它到底有多“静态类型”?!
  • Curl 编译错误:没有函数重载;它也不会检查函数体,除非它被调用,那么它到底是如何“静态类型化”的呢?它是完全编译的还是解释的?!
  • Gosu 是一个糟糕的笑话,它根本不可用:不能用一种方法编写和实现简单的接口(错误:ClassFormatError: Illegal field modifiers)。谁真正使用这种语言?!

顺便说一句:当我尝试将 Java 对侦听器的支持放入单独的类时,我想到了这个问题(在许多类中有:List ... addListener(...) ... removeListener(. ..))

C++几乎可以工作:

template <typename T>
class Template { public: void function(T i) {} };
class Composed : public Template<int>, public Template<double> { };

Composed composed;
composed.Template<int>::function(3); //i want: composed.function(3);
((Template<double>&)composed).function(2.5); //i want: composed.function(2.5);

编辑:在 C++ 中,问题是隐藏继承函数。也可以看看 Function with same name but different signature in derived classWhy does an overridden function in the derived class hide other overloads of the base class?

编辑 2:在 C++ 中,使用模板和部分特化,有可能使用肮脏的技巧来更简单地使用 trait:

#include <iostream>
#include <typeinfo>

class Void { };
template <class A, class B> class CleverTrait;
template <class A, class B> class CleverTrait;
template <class A> class CleverTrait<A, Void>
{
public:
    void function(A arg) { std::cout << "Hello for type " << typeid(A).name() << std::endl; }
};
template <class A, class B> class CleverTrait<A, CleverTrait<B, Void> > : public CleverTrait<B, Void>
{
public:
    using CleverTrait<B, Void>::function;
    void function(A arg) { std::cout << "Hello for type " << typeid(A).name() << std::endl; }
};

class ComposedByClever : public CleverTrait<double, CleverTrait<int, Void> > { };

int main()
{
    ComposedByClever composedByClever;
    composedByClever.function(5);
    composedByClever.function(2.3);
    return 0;
}

这意味着这个 C++ 中的特定示例有效,但是如果不相关的特征共享函数名,则无法在 C++ 中继承和使用所有函数。

编辑 3:我还应该检查任何支持 mixins 的编程语言:http://en.wikipedia.org/wiki/Mixins#Programming_languages_that_use_mixins

  • D 有效,但只能通过字符串操作 mixin,所以 在这种情况下会破坏重构mixin(GenerateSomething!("IfClassNameHereManualRenaming"));

编辑4:添加“Gosu”语言注释。

编辑 5:Gosu 编程语言已更新 0.10.2,修复了接口损坏问题。然而,即使他们声称已经具体化了泛型和委托,委托+具体化的泛型也不起作用。

【问题讨论】:

  • public: using Template&lt;int&gt;::function; using Template&lt;double&gt;::function; 放在Composed 类中可以使C++ 示例在没有Template&lt;...&gt;:: 或强制转换(如您所愿)的情况下工作。
  • 你也可以在 C++ 中使用它:public: template&lt;typename T&gt; void function(T i) { static_cast&lt;Template&lt;T&gt;*&gt;(this)-&gt;function(i); }(或者只是 Template&lt;T&gt;::function(i) 而不是强制转换,尽管这可能隐藏静态成员函数的问题:当它们不被继承时,它会仍然有效)。
  • 另一个奇怪的想法:在 C++ 中,您可以通过使用 CRTP 的变体将多继承转换为单继承,例如class Composed : public Template&lt;int, Template&lt;double&gt;&gt;,其中Template&lt;int,..&gt; 派生自Template&lt;double&gt; 并使用自己的using 指令来重载function。有了这个技巧,您就不必为每个基类手动指定 using
  • @DyP:(使用)我不知道使用,谢谢。但是我仍然必须列出所有功能,这违背了 trait 的目的。 (静态转换)类似于 using,但如果超过 2x 继承就会变得更聪明。
  • @DyP:(模板)它可以工作,它可以在没有可变参数模板的情况下完成,也许也可以使用它们,我还没有使用它们。

标签: templates generics multiple-inheritance overloading


【解决方案1】:

C++:类似于 CRTP (see comment to OP) 的奇怪想法本来应该更像:

#include <typeinfo>
#include <iostream>

struct Dummy
{
private:
  // dummy type to prevent overload resolution from ever choosing this overload
    struct ParamDummy { explicit ParamDummy(); };
public:
    void function(ParamDummy);
};

template<typename T, typename Base = Dummy>
struct Template
    : Base
{
    using Base::function;
    void function(T i) { std::cout << typeid(T).name() << std::endl; }
};

struct SecondBaseClass
{
    void function2() { std::cout << "function2" << std::endl; }
};

struct Composed
    : Template<int, Template<double>>, SecondBaseClass
{};

int main()
{
    Composed c;
    c.function(5.0);
    c.function(5);
    c.function2();
}

对于Template 中的每个不同的成员函数名称,您需要一个using 指令。因此,数量仅取决于当前类中成员函数的数量,而不取决于基类。

它在某些方面与多重继承不同,但它允许简单的函数重载。

如果基类只共享一些而不共享所有成员函数,那就更麻烦了。

【讨论】:

  • 简单的函数重载——但只能来自相同的特征,否则你不知道你应该“使用”什么
  • @peenut 您在您的 自己的 类的所有函数名称上使用using 指令,您不需要知道基类的函数名称。如果您的基类没有像您自己一样命名的成员,也许您可​​以插入一些技巧使其也可以工作。
  • @peenut 事实上,如果你想重载函数(堆叠式单继承)和不相关基类的多重继承,你可以使用这个技巧。
猜你喜欢
  • 2011-12-30
  • 2014-01-09
  • 1970-01-01
  • 2016-09-26
  • 2011-02-11
  • 1970-01-01
  • 2011-02-09
相关资源
最近更新 更多