C++17 之前的 CTAD 替代品?

问题描述 投票:0回答:1

(或者:“如何存储不允许使用
auto
的模板参数推导函数的返回值”)

我正在开发一个由多个类模板组成的通用 C++ 框架 允许结合彼此的专业知识。 由于外部原因,语言版本仅限于 C++14。 在非通用用户代码中使用我的框架最终会导致复杂的模板专业化,例如

MyType<foo<bar, baz, quuz<quz>, zip<zap<zoo>>> myObj{
    foo<bar, baz, quuz<quz>, zip<zap<zoo>>{
        bar{},
        baz{},
        quuz<quz>{
            quz{}
        },
        zap<zoo>{
            zoo{}
        }
    }
};

当然,模板参数类型不必等于构造函数参数的类型, 但就我目前的代码而言,这种情况经常发生。 显示的代码只是真实代码的漫画(更多类型/模板), 但这应该足以指出我的问题 (如果您需要一些可编译的示例代码来进行评估,请告诉我):

当我引用所需的所有模板参数时,这会在代码中引起很多噪音, 特别是对于那些必须重复命名的类型。 类型别名 (

using
) 看起来并不是完美的补救措施,因为该示例需要 还有很多这样的。

我检查了模板参数推导的可能性,并且 我了解到 C++14 仅支持函数模板的模板参数推导 (比如经常讨论的

std::make_pair
的例子),但是 类模板参数推导(CTAD) 在 C++17 之前不可用。

使用基于函数的模板参数推导(和“make 函数”), 我可以“简化”上面示例代码右侧的对象初始化表达式, 这会导致类似的事情

MyType<foo<bar, baz, quuz<quz>, zip<zap<zoo>>> myObj = make_obj( 
    make_foo(
        bar{},
        baz{},
        make_quuz(quz{}),
        make_zap(zoo{})
    )
);

在可以使用

auto
的上下文中,我什至可以达到简短且富有表现力的代码的目标,例如

auto myObj = make_obj(make_foo(bar{}, baz{}, make_quuz(quz{}), make_zap(zoo{})));

但这似乎仅在某些情况下才可能,例如,

myObj
是局部变量。

我想实现一个框架库,使用户能够创建自己的、非通用的 基于我的模板的课程,但他们不必重复(并记住)所有课程 用于实现其类实现的类型(= 模板特化),如下所示:

class UserType
{
    public:
        UserType() : m_frameworkImplementation{make_foo(/*...*/)} {}
    private:
        // This is illegal code, of course. Only to show what I'd like to realize...
        auto m_frameworkImplementation;
};

可悲的是,我无法在这里对

auto
做任何事情,而且我无法用
auto
替换
MyType
如果我不将所有模板参数复制到其中。

我还用

decltype
、lambdas和其他东西做了一些徒劳的尝试,但我什至没有获得 关于可能的解决方案的提示(在这里展示任何这些失败的尝试都让人感到尴尬)。 似乎没有办法推断出类模板构造的特殊类型,或者 函数模板推导的专业化的返回值(例如,“make function”), 在需要推导类型来实例化成员变量的类型时。

我忽略了什么?我是否必须等到可以使用 C++17 或 C++20 才能达到预期结果?

c++ templates c++14 template-argument-deduction ctad
1个回答
0
投票

C++14 具有自动返回类型推导,因此您可以使用它来“隐藏”您的类型。

#include <utility>

template <typename T>
class UserType
{
    public:
        UserType(T&& val) : m_frameworkImplementation{std::move(val)} {}
    private:
        T m_frameworkImplementation;
};

auto make_foo()
{
    return UserType<int>(6);
}

int main()
{
    auto type = make_foo();
}

用户 IDE 应该仍然能够推断类型,因为

make_foo
UserType
都将是模板化代码(并且不能跨越翻译单元边界)。

© www.soinside.com 2019 - 2024. All rights reserved.