简体   繁体   English

模板静态函数模板类类型推导

[英]template static function template class type deduction

I want to make static function in singletone template class, that would be able to deduct types of template class.我想在单调模板类中创建静态函数,这样就可以扣除模板类的类型。 The problem is, that calling static function from template class requires explicit type.问题是,从模板类调用静态函数需要显式类型。 The only workaround that I've came up with was template function instead if template member function.我想出的唯一解决方法是模板函数,而不是模板成员函数。

Here is an example.这是一个例子。 The problem is that foo4 part is not working问题是 foo4 部分不起作用

template <class T>
class Foo
{
private:
    Foo() {}
    Foo(const Foo&) = delete;
    Foo& operator= (const Foo&) = delete;

public:
    static auto& Instance()
    {
        static Foo foo{};
        return foo;
    }

    template<class K> static
    auto& DeductInstance(const K&)
    {
        static Foo<K> foo{};
        return foo;
    }

};

template<class K>
auto& DeductInstance(const K&)
{
    return Foo<K>::Instance();
}

void main()
{
    auto& foo1 = Foo<int>::Instance(); //OK
    auto& foo2 = Foo<int>::Instance(); //OK (return same example as foo1)
    auto& foo3 = DeductInstance(123); //OK
    auto& foo4 = Foo::DeductInstance(123); //NOT WORKING
}

The syntax you're asking for is theorically possible using injected class names. 从理论上讲,您可以使用注入的类名来请求语法。 That would make Foo:: resolve to a particular, unrelated Foo<x>:: . 这会使Foo::解析为特定的,不相关的Foo<x>:: Here's an example: 这是一个例子:

struct BaseFoo {
    template<class K> static
    auto& DeductInstance(const K&);
};

template <class T>
struct Foo  {
    static auto& Instance() {
        static Foo foo{};
        return foo;
    }
};

template<>
struct Foo<void> : private BaseFoo {
    using BaseFoo::DeductInstance;
};

template<typename K>
auto& BaseFoo::DeductInstance(const K&)
{
    return Foo<K>::Instance();
}

using MakeFooAvailable = Foo<void>;

struct Dummy : MakeFooAvailable {
    auto& bar() {
        // Syntax working
        return Foo::DeductInstance(234);
    }
};

In the class Dummy , there's a injected class name for the base class Foo , resolving it to Foo<void> . Dummy类中,为基类Foo注入了一个类名,将其解析为Foo<void> Then, Foo<void> is making BaseFoo::DeductInstance available for name resolution in its scope. 然后, Foo<void>使BaseFoo::DeductInstance在其范围内可用于名称解析。


I would advise not using this solution because it's a clever one. 我建议不要使用此解决方案,因为它是一个聪明的解决方案。 Clever generally mean surprising. 聪明通常意味着令人惊讶。 Programmers don't expect seeing Foo as a non template when it is. 程序员不希望将Foo视为非模板。 The best solution I think would be: 我认为最好的解决方案是:

auto& foo1 = Foo<int>::Instance(); //OK

The simpler, the better. 越简单越好。

I have to admit that I dont understand completely what you are trying to do. 我必须承认,我不完全理解您要做什么。 However, you can do either of the following two: 但是,您可以执行以下两个操作之一:

struct foo {
    template <typename T> 
    static T deduce(const T& t) { 
        return {};
    }
};

template <typename T> 
T deduce_free(const T& t) {
    return {};
}

int main() {
    auto x = foo::deduce(1);
    auto y = deduce_free(1);
}

But you cannot call a method (whehter static or not) on some instance of bar<T> before you know what T is. 但是,在知道T是什么之前,您无法在bar<T>某些实例上调用方法(是否为静态)。

Things have changed a bit with C++17 which has class template argument deduction , though as far as I know this works for constructors, so you would still need a foo<int> first before you could call a foo<int>::deduce() I am too unexperienced with that to say something not wrong ;). 事情已经改变,与C ++ 17位具有类模板参数推导 ,但 据我知道这个工程的建设者,所以你仍然需要一个 foo<int>第一之前,你可以调用一个 foo<int>::deduce() 我对此没有经验,所以说不出什么错;)。

It's 2021 and we have CTAD, but I don't think it helps.现在是 2021 年,我们有 CTAD,但我认为它没有帮助。 I think this is very close to what you (and I!) want:我认为这非常接近你(和我!)想要的:

// A helper struct to provide Foo with a default template 
// that isn't useful for instantiation:
struct DoNotInstantiate { DoNotInstantiate() = delete; };

template <class T = DoNotInstantiate>
class Foo
{
private:
    Foo() {
        static_assert(!std::is_same_v<T, DoNotInstantiate>, "You can't actually instantiate it with the default, it's just to make the static function work."); // Optional
    }
    // ...

public:
    // ...

    template<class K> static
    auto& DeductInstance(const K&)
    {
        static Foo<K> foo{};
        return foo;
    }
};

So you can call Foo<>::DeduceInstance(bar);所以你可以调用Foo<>::DeduceInstance(bar); . . You still have to write the <> but otherwise, it's perfect, I think.您仍然必须编写<>但除此之外,我认为它是完美的。

If you don't want that and really want to be able to call a static on a template, naming just the template name, there's this:如果您不希望那样并且真的希望能够在模板上调用静态,仅命名模板名称,则可以使用以下方法:

template <template<typename ...> class FooType, typename T>
auto DeduceInstance(const T& x) {
    return FooType<T>::DeduceInstance(x);
}

which lets you call DeduceInstance<Foo>(x) where Foo is just a template.这让您可以调用DeduceInstance<Foo>(x) ,其中Foo只是一个模板。 But that feels round-about.但这感觉是圆的。 I prefer Foo<>::DeduceInstance(x);我更喜欢Foo<>::DeduceInstance(x); . .

It would be nice if CTAD let you write如果 CTAD 让你写就好了

template <class T>
Foo::DeductInstance(const T&) -> T&;

or maybe it would be或者它可能是

template <class T>
Foo::DeductInstance(const T&) -> Foo<T>::DeduceInstance(const T&);

or something similar, basically saying that if you use the template name without a type to call a static, use the argument list to dope out which template the caller was talking about.或类似的东西,基本上是说如果您使用没有类型的模板名称来调用静态,请使用参数列表来掺杂调用者正在谈论的模板。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM