【问题标题】:deduce member variable type推断成员变量类型
【发布时间】:2020-11-09 19:53:26
【问题描述】:

已编辑:我忘记了回调“捕获”outerthis 指针。

我正在尝试初始化某个类及其成员。

该类没有模板化。

它的成员模板化的。它采用模板的“函数类型”来进行封装类的回调。 (我不能使用std::function,因为这是时间关键代码。)

此外,我希望编译器会推断出回调对象的模板类型(给成员。)

代码看起来像这样(假设所有样板都存在):

template<typename func_t>
class inner : public inner_abstract_base
{
public:
    func_t m_cb;
    inner(func_t cb):m_cb(cb){}
};

class outer
{
    Int member_fun(int);
public:
    /*********first try****************/
    // inner member{[this]{return this->member_fun(123);}}

    /*********second try***************/
    // inner member;
    // outer():member([this]{return this->member_fun(321);})
    // {}

    /*********third try****************/
    // auto lamb = [this]{return this->member_fun(987);};
    //This or in the constructor initialization list
    // inner<decltype(lamb)> member{lamb};

    /*********fourth try***************/
    // friend int func();
    // inner<decltype(func)> member{func};

    /*********fifth try***************/
    // std::unique_ptr<inner_abstract_base> member_p;
    // outer():member_p([]{return 666;})
    // {}

    /*********sixth try***************/
    // inner<decltype(some_free_func)> member{some_free_func};

};

第一次尝试

我不确定为什么它不起作用。我猜在这种类型的初始化中(在类定义中)编译器不会猜测模板类型。可能是因为它使用了聚合初始化(是吗?如果是,为什么聚合初始化不支持模板类型推导)

第二次尝试

这不起作用,因为在定义中没有给出模板参数。仅在构造函数中调用它(在运行时),因此无法进行模板类型推导。

第三次尝试

非静态成员不能用auto 声明(为什么??) - 所以成员lamb 一开始就不能被初始化。

第四次尝试

我不喜欢这种方法,因为它比原始设计更进一步,但尽管如此 - 由于某种我无法理解的原因,它不起作用。

第五次尝试

这太过分了。我认为这个不起作用,因为我没有正确使用它。可能是因为我没有将它转换为儿子类型进行分配......(如何?)。即使使用“正确”的用法,类型推导也可能不适用于带有指针的设备。

第六次尝试

只是为了好玩 - 免费的乐趣!与朋友功能不起作用的原因相同(合理)。

底线

在捕获/不捕获this 指针的情况下,您如何解决这个惨败?

如何让编译器推导出成员变量的类型?

或者在给定的情况下更具体?

*我很抱歉来回编辑...

【问题讨论】:

  • C++17(或 C++20),我想。
  • 第 6 个应该是:inner&lt;decltype(&amp;some_free_func)&gt; member{&amp;some_free_func};
  • 第 5 个应该是 outer():member_p(std::unique_ptr{new Inner{[]{return 666;}}}) {}(CTAD 使用了两次)。

标签: c++ class templates type-deduction


【解决方案1】:

推导出成员变量类型

在 C++ 中是不可能的。不推导出成员变量类型。


  1. 我不确定为什么它不起作用。

First 不起作用,因为您没有指定成员类型的模板参数,并且无法推断。

...可能是因为它使用聚合初始化

没有。

  1. 不能用 auto 声明非静态成员(为什么??)

因为auto需要类型推导,成员变量的类型没有推导。

  1. 由于某种我无法理解的原因,它不起作用。

它不能工作的一个原因是因为你试图指定一个函数类型作为模板参数,而内部类不能有一个函数类型的成员变量。由于名称查找问题,它似乎在此之前失败了。

  1. 我认为这个不起作用,因为我没有正确使用它。

您尝试使用 lambda 参数初始化唯一指针。唯一指针根本没有构造函数接受这样的参数。


你如何解决这个惨败?

一种方法:不要尝试定义成员变量。以成员函数为例:

constexpr auto member_fun()
{
    return inner{[]{return 123;}};
}

由于您的 lambda 没有内部状态,因此函数指针也可以工作:

using fun = int();
inner<fun*> member{[]{return 123;}};

这可能比函数替代更难优化,因为通常不容易证明函数指针没有改变。并且 const 成员是有问题的。

【讨论】:

  • 谢谢!我还有一些疑问:为什么不推导出成员变量类型?你能解释一下你的第一个解决方案吗?您可以考虑编辑后的问题吗?抱歉打扰了...
【解决方案2】:

你的符号有点奇怪,但你得到的最接近的是第三次尝试。稍微改变一下就可以了,你会得到:

int lamb() { return 50; }

template<typename func_t>
class inner
{
public:
    func_t m_cb;
    inner(func_t cb):m_cb(cb){}
};

class outer
{
public:
    inner<decltype(&lamb)> member{lamb};
};

int main()
{
    outer o;
}

请注意,您尝试使用decltype(lamb) 时遇到的问题是它为您提供了函数类型,即在我的情况下它扩展为int(),并且您不能声明该类型的变量。但是你知道你可以声明什么变量吗?没错,一个函数指针,即decltype(&amp;lamb)

或者,您可以将原始 decltype(lamb) 放入 function&lt;&gt; 对象中,然后让自动转换接管:

#include <functional>

int lamb() { return 50; }

template<typename func_t>
class inner
{
public:
    std::function<func_t> m_cb;
    inner(func_t cb):m_cb(cb){}
};

class outer
{
public:
    inner<decltype(lamb)> member{lamb};
};

int main()
{
    outer o;
}

【讨论】:

  • 谢谢!你提到std::function的地方,是不是比模板效率低?
  • 它是一个模板,它和你放入的东西一样高效。如果你在其中放置一个指向函数的指针,调用它会生成一个常规的函数调用指令。如果您放置一个 currying lambda 函数,它将创建您必须手动创建的相同函子。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多