首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >声明template<typename Foo<T>>而不是template<typename T>

声明template<typename Foo<T>>而不是template<typename T>
EN

Stack Overflow用户
提问于 2022-02-14 10:02:24
回答 3查看 123关注 0票数 1

我有一个template<typename T> class Foo

我想声明一个函数,它可以返回任何类型的Foo。我会这样做:template<typename T> Foo<T> bar();

但这意味着我必须像这样使用它:Foo<SomeConcreteT> f = bar<SomeConcreteT>();SomeConcreteT可以非常长、笨重、烦人而不得不打印出来。

但是,我确实有一些

代码语言:javascript
复制
using AppleFoo = Foo<ABunchOfStuffForApples>;
using BananaFoo = Foo<SomethingElseForBananas>;
// ...

我更喜欢这样调用bar:AppleFoo f = bar<AppleFoo>();,这样我就不必一直键入ABunchOfStuffForApples,从概念上讲,AppleFooABunchOfStuffForApples更多地告诉读者应该发生什么。

我可以通过在using TType = T中添加Foo和类似于以下的助手函数来实现这一点:

代码语言:javascript
复制
template<typename F>
F bar()
{
    return bar<F::TType>();
}

但是这是丑陋和容易出错的(例如调用bar<SomethingThatIsNotAFoo>())。

有更干净的方法吗?

是否有一种更一般的方法来测试某些类型是否是SomethingKnown<SomethingUnknown>,例如在static_assert

EN

回答 3

Stack Overflow用户

发布于 2022-02-14 10:10:50

您可以假装有返回类型的扣减,方法是让bar是一个非模板,返回带有operator Foo<T>的代理。

代码语言:javascript
复制
template <typename T>
struct Foo {
    /* ... */
};

namespace detail {
    struct bar_t {
        template <typename T>
        operator Foo<T>() { /* current implemenation of bar */ }
    };
}

detail::bar_t bar() { return {}; }

using AppleFoo = Foo<struct Apple>;

int main() {
    AppleFoo f = bar();
}
票数 1
EN

Stack Overflow用户

发布于 2022-02-14 10:22:13

您可以创建一个特征来知道它是否是Foo,并提取其模板参数:

代码语言:javascript
复制
template <typename T>
struct is_foo : std::false_type {};

template <typename T>
struct is_foo<Foo<T>> : std::true_type
{
    using type = T;
};

然后

代码语言:javascript
复制
template<typename FOO>
FOO bar()
{
    static_assert(is_foo<FOO>::value);

    using T = typename is_foo<FOO>::type;
    // ...
}
票数 1
EN

Stack Overflow用户

发布于 2022-02-14 12:33:22

作为替代,如果您可以更改调用语法,则可以传递一个标记,

代码语言:javascript
复制
template <typename T> struct tag {};

然后

代码语言:javascript
复制
template<typename T>
Foo<T> bar(tag<Foo<T>>)
{
    return bar<T>();
}

的用法类似于

代码语言:javascript
复制
using AppleFoo = Foo<ABunchOfStuffForApples>;

auto bar1 = bar(tag<AppleFoo>{});
auto bar2 = bar(tag<Foo<ABunchOfStuffForApples>>{});
// auto is AppleFoo and so Foo<ABunchOfStuffForApples>

如果不喜欢接口中的标记,仍然可以将其用作实现:

代码语言:javascript
复制
template<typename T>
Foo<T> bar_impl(tag<Foo<T>>)
{
    // implementation, such as return Foo<T>(); 
}

// Possibly other specialization for Foo<std::vector<T>>, Foo<int>, .. 

template<typename T>
auto bar()
{
    return bar_impl(tag<T>{});
}

与使用

代码语言:javascript
复制
using AppleFoo = Foo<ABunchOfStuffForApples>;

auto bar1 = bar<AppleFoo>();
auto bar2 = bar<Foo<ABunchOfStuffForApples>>();
// auto is AppleFoo and so Foo<ABunchOfStuffForApples>
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71110004

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档