简体   繁体   English

使用派生模板类和智能指针进行模板推导

[英]Template deduction with derived templated class and smart pointers

Let's say I have a templated base class, and a templated class that derives from it:假设我有一个模板化基类,以及一个派生自它的模板化类:

template <typename T>
class Base {};

template <typename T>
class Derived : public Base<T> {};

Further, I've got a function that wants to accept a shared pointer to any Base<T> or subclass, and be able to easily use the T parameter as part of its signature:此外,我有一个函数想要接受指向任何Base<T>或子类的共享指针,并且能够轻松地使用T参数作为其签名的一部分:

template <typename T>
T DoSomething(std::shared_ptr<Base<T>>);

I want to be able to call it, with a deduced T , with shared pointers to Base<T> or anything that derives from it:我希望能够使用推导的T调用它,并使用指向Base<T>或从它派生的任何内容的共享指针:

DoSomething(std::make_shared<Base<T>>());
DoSomething(std::make_shared<Derived<T>>());

Of course the latter doesn't work, because type deduction fails.当然后者不起作用,因为类型推导失败。

How can I modify the signature of DoSomething to allow it to work?如何修改DoSomething的签名以使其工作? I've seen plenty of answers in the case where Base and Derived aren't templates, but I'm not sure how to do it if I still want to deduce T (for example to use it as a return type, as above).BaseDerived不是模板的情况下,我已经看到了很多答案,但是如果我仍然想推导出T (例如将其用作返回类型,如上所述),我不知道该怎么做.

Ideally this would fail for shared pointers to non-derived inputs (and non-shared pointers) at overload resolution time.理想情况下,这对于在重载解析时指向非派生输入(和非共享指针)的共享指针会失败。

You can use a template template parameter in your function, then a static_assert to enforce your requirement.您可以在函数中使用模板模板参数,然后使用static_assert来强制执行您的要求。

#include <memory>
#include <vector>

template <typename T>
class Base {};

template <typename T>
class Derived : public Base<T> {};

template <typename T, template <typename> typename U>
T DoSomething(std::shared_ptr<U<T>>) {
    static_assert(std::is_base_of_v<Base<T>, U<T>>, "Requires a std::shared_ptr to Base of class derived from Base");
    return T{};
}

int main() {
    auto foo = std::make_shared<Derived<int>>();
    auto baz = std::make_shared<Base<int>>();
    auto bar = std::make_shared<std::vector<int>>();

    DoSomething(foo);
    DoSomething(baz);
    DoSomething(bar); // Fails, std::vector<int> is not derived from Base<int>
}

Edit编辑
If DoSomething is overloaded we can use SFINAE to disable it instead of the static_assert .如果DoSomething被重载,我们可以使用 SFINAE 来禁用它而不是static_assert That would look as follows.这将如下所示。

#include <memory>
#include <vector>

template <typename T>
class Base {};

template <typename T>
class Derived : public Base<T> {};

template <typename T, template <typename> typename U, std::enable_if_t<std::is_base_of_v<Base<T>, U<T>>, int> = 0>
T DoSomething(std::shared_ptr<U<T>>) {
    return T{};
}

int main() {
    auto foo = std::make_shared<Derived<int>>();
    auto baz = std::make_shared<Base<int>>();
    auto bar = std::make_shared<std::vector<int>>();

    DoSomething(foo);
    DoSomething(baz);
    DoSomething(bar); // Error, no matching function
}

Even though, there is already an accepted answer to this problem by @super, here is a slightly different (but probably less elegant way) of using SFINAE:尽管如此,@super 已经为这个问题提供了一个公认的答案,这里是使用 SFINAE 的一种略有不同(但可能不太优雅的方式):

#include <memory>
#include <type_traits>

template <typename T>
class Base {};

template <typename T>
class Derived : public Base<T> {};

template <template <typename> typename U, typename T>
std::enable_if_t<std::is_base_of<Base<T>,U<T>>::value, T>
DoSomething(std::shared_ptr<U<T>>)
{
    return T{};
}

int main()
{
    auto foo = std::make_shared<Base<int>>();
    auto bar = std::make_shared<Derived<int>>();
    
    DoSomething(foo);
    DoSomething(bar);

    return 0;
}

Live demo: godbolt .现场演示: godbolt

Why do I consider this less elegant?为什么我认为这不那么优雅? This is because the signature of the function changed and now has std::enable_if_t<...> as return type, even though it is finally deduced as T (for valid input, of course).这是因为函数的签名发生了变化,现在将std::enable_if_t<...>作为返回类型,即使它最终被推导出为T (当然,对于有效输入)。

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

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