【问题标题】:Is there a succinct way to derive a member's type during construction?在构造过程中是否有一种简洁的方法来导出成员的类型?
【发布时间】:2013-05-22 05:26:20
【问题描述】:

我有:

  • 模板例程unarchive 接受一个字典和一个键并基于传递的模板类型 (T) 可以专门生成一个T
  • struct 的构造函数,利用 unarchive 构造其成员

一个例子可能如下:

template <typename T>
T unarchive(const dictionary_t&, key_type key);

struct foo
{
    foo(const dictionary& archive) :
        value_m(unarchive<decltype(value_m)>(archive, value_key))
    { }

    some_value_type value_m;
};

在这里使用unarchive&lt;decltype(value_m)&gt; 的好处是我可以更改value_m 的类型而无需更新这行代码——类型始终遵循成员变量的类型。

我遇到的问题更美观:它非常冗长。目前我有一个宏:

#define UNARCHIVE_FOR(var) unarchive<decltype(var)>

foo的构造函数变化如下:

foo(const dictionary& archive) :
    value_m(UNARCHIVE_FOR(value_m)(archive, value_key))
{ }

现在我得到了一个更简洁但更丑陋的结果。没有宏能达到同样的效果吗?我想要的是类似于:

foo(const dictionary& archive) :
    value_m(unarchive<value_m>(archive, value_key))
{ }

如何做到这一点?

【问题讨论】:

  • 为什么不unarchive(m,archive,value_key)
  • 参数类型推导呢? unarchive(value_m, archive, value_key) - 您还可以提供适配器功能,例如作为静态成员。
  • 我想过这一点,但该变量当时尚未完全构造,因此不想给人留下任何印象,即该变量实际上会在例程中使用 - 我想传递它作为模板参数,以强调它的类型是被派生的。
  • @fbrereto 在这种情况下,decltype 在 IMO 中表现得非常清晰和富有表现力。
  • unarchive(&amp;value_m,archive,value_key) 然后。

标签: c++ c++11 constructor decltype type-deduction


【解决方案1】:

在这里使用 unarchive 的好处是我可以更改 value_m 的类型,而无需更新这行代码——类型始终遵循成员变量的类型。

另一种方法是为value_m 类型创建一个别名,并从构造函数初始化列表中删除decltype(value_m)

struct foo
{
    using value_type = int;

    foo(const dictionary_t& archive, const key_type value_key) :
        value_m(unarchive<value_type>(archive, value_key))
    { }

    value_type value_m;
};

unarchive&lt;value_type&gt; 仍然遵循value_m 的类型。如果担心通过不更改 value_type 来更改 value_m 的类型,则可以添加 static_assert 以确保 value_m 的类型与 value_type 相同:

static_assert(std::is_same<decltype(value_m), value_type>::value,
              "'value_m' type differs from 'value_type'");

或者根据value_m的类型设置别名:

int value_m;
using value_type = decltype(value_m);

如果您仍然认为构造函数初始化列表很冗长,请提供一个调用unarchive() 函数的static 包装函数:

struct foo
{
    using value_type = int;

    foo(const dictionary_t& archive, const key_type value_key) :
        value_m(unarchive_(archive, value_key))
    { }

    static value_type unarchive_(const dictionary_t& d, key_type k)
    {
        return unarchive<value_type>(d, k);
    }

    value_type value_m;
};

说了这么多:

value_m(unarchive<decltype(value_m)>(archive, value_key))

不是那么冗长,而是准确地说明了意图。

【讨论】:

  • 我知道这不是 冗长的,你是对的。也就是说,重复指定类型似乎很草率,并且不可避免地会导致某些人在以后不匹配它们。我宁愿指定一次类型并完成它。 usingdecltype 的声明也非常令人兴奋,顺便说一句。
【解决方案2】:

这有点老套,但是如何使用模板化转换运算符为存档引入包装类:

class wrapper {
  const dictionary_t& dict_m;
  const key_type key_m;
public:
  wrapper(const dictionary_t& d, key_type k) :
    dict_m(d), key_m(k) {}
  template <class T> operator T () const {
    return unarchive<T>(dict_m, key_m);
  }
};

所以你可以初始化:

foo(const dictionary_t& archive, const key_type value_key) :
    value_m(wrapper(archive, value_key))
{}

【讨论】:

  • 啊,聪明!我喜欢它通过使用隐式转换使事情比以前更简洁。我得再考虑一下这个想法,谢谢。
猜你喜欢
  • 2011-06-17
  • 1970-01-01
  • 2019-08-24
  • 2019-01-27
  • 1970-01-01
  • 1970-01-01
  • 2017-03-27
  • 2011-11-05
相关资源
最近更新 更多