0

考虑以下具有模板变量并使用模板别名和自动类型推导的非类模板。

template<typename T>
using Type = T;

using TypeA = Type<int>;
using TypeB = Type<double>;

class Foo {
private:
    template<typename T>
    static Type<T> type_;
public:
    template<typename T>
    explicit Foo( Type<T> type ) { type_<T> = type; }

    // non static member
    template<typename T>
    auto bar() { return type_<T>; }

    // static member
    template<typename T>
    static auto bar(T _x_ = 0) { return type_<T>; }
};

以及使用它的程序:

// has to be defined in some cpp file.
template<typename T>
Type<T> Foo::type_;

int main() {
     TypeA a{ 7 };
     TypeB b{ 3.41 };

     Foo f1( a );
     Foo f2( b );

     auto x = Foo::bar<TypeA>();
     auto y = Foo::bar<TypeB>();

     std::cout << "static auto f1: " << x << '\n';
     std::cout << "static auto f2: " << y << '\n';

     std::cout << "member f1: " << f1.bar<TypeA>() << '\n';
     std::cout << "member f2: " << f2.bar<TypeB>() << '\n';

     return 0;
};

输出

static auto f1: 7
static auto f2: 3.41
member f1: 7
member f2: 3.41

在类声明中;我T在静态版本中使用了一个参数并将其默认为 0,以便可以在没有任何参数的情况下调用它。如果不添加它,那么将无法重载没有参数或参数列表具有相同参数的静态和非静态成员函数。

这会被认为是快速修复还是黑客攻击,或者这是一种能够为具有相同名称和功能的静态和非静态成员函数提供相同类型接口的可能方式?

函数参数或参数是一个虚拟参数,对内部值绝对没有任何作用。

回来并再次阅读后,我可以看到一些混乱来自于我忽略了这更多地与变量模板的使用和能够访问它们有关的事实。

所以我认为真正的问题应该是:关于变量模板成员并且它们必须是静态的,通过成员函数访问它们的首选方式是什么:通过静态或非静态,或者没有偏好和选择留给程序员?

最后一件事;是否有任何不可预见的问题可能导致这种类型的设计模式 - 接口的未来后果?

4

1 回答 1

2

这是否被认为是一种快速修复或破解,或者这是能够为同名的静态和非静态成员函数提供相同类型的接口的正确方法?

没有适当的方法来完成不适当的目标。除此之外,您的版本不提供相同的界面。非静态版本需要显式模板参数,而静态版本可以使用演绎,如f1.bar(1). 我不确定我是否建议在这种情况下使用推论(因为代码更神秘),但提供了这种可能性。你的不正当目标甚至没有达到。

如果函数具有相同的功能(如您的示例中),那么非静态版本是毫无意义的开销。只提供静态版本,如果有人想从对象调用它,那没关系。

如果函数在功能上不一样(也许你的例子过于简单了?),那么给它们起相同的名字是一个坏主意。这包括非静态版本可以根据*this. 至少在这种情况下,静态版本应该重命名为类似的东西,bar_no_object()以区别于依赖对象的版本。

最后一件事;是否有任何不可预见的问题可能导致这种类型的设计模式 - 接口的未来后果?

好吧,基本上你是在为自己的混乱做准备。其他人都会期望Foo::bar()Foo{}.bar()调用相同的(静态)函数,而您正试图打破它。

注意编译器的消息。其他人的这种期望是您无法“重载没有参数或参数列表具有相同参数的静态和非静态成员函数”的原因。你试图制造歧义,编译器阻止了你。有充分的理由。在询问您的解决方法是否有效之前,也许您应该询问编译器阻止您的原因?

于 2019-07-21T00:44:10.070 回答