【问题标题】:Function parameter type using decltype使用 decltype 的函数参数类型
【发布时间】:2015-09-21 02:52:27
【问题描述】:

注意:这个问题中提供的示例不是生产代码,完全没有意义。它只是为了说明我的问题。

我在测试decltype的可能性,尤其是用来推导函数参数类型的时候,遇到了问题:

假设有两个类的结构如下:

struct ClassInt
{
    // Note: no default ctor
    ClassInt(int value)
        :   m_Value(value)
    {}

    int  m_Value;
};

struct ClassDouble
{
    // Note: no default ctor
    ClassDouble(double value)
        :   m_Value(value)
    {}

    double  m_Value;
};

现在,我编写了一个函数,它(以某种方式)通过字符串检索类型参数(应该是上述之一)的实例,并将给定值分配给它的 m_Value 成员:

template< typename Ty >
Ty* get_fake_ptr() { return nullptr; }


// Retrieve pointer to Ty object by name and assign its value member.
// The problem is that we don't actually have an instance of Ty at the point
// where we want to define the type of the parameter "value".
template< typename Ty >
void assign(std::string name, decltype(get_fake_ptr<Ty>()->m_Value) value)
{
    // Somehow get pointer to a Ty object by name
    Ty* obj = ????;

    // Assign
    obj->m_Value = value;
}

现在,参数value 的类型取决于类型参数,因为使用的类在成员m_Value 的类型上有所不同。如您所见,我使用decltype 解决了它。现在,通常情况下,您会在参数上使用decltype,如下所示:

template<typename Ty>
void assign(Ty& obj, decltype(obj.m_Value) value);

但这显然不可能,因为实际实例是在函数体中检索的,因此在声明函数参数时不可用。

我通过使用模板函数get_fake_ptr 将它组合在一起,它只返回一个匹配类型的nullptr,所以我有一个编译器可以用来确定成员类型的“伪实例”。它有效:

现在,正如我所说,这对我来说似乎真的很老套。所以:

有没有更好的方法来解决这个问题?

谢谢!

【问题讨论】:

  • 您可以使用decltype(std::declval&lt;T&gt;().m_Value) 来推断T 的m_Value 成员的类型,而不是使用您的get_fake_ptr() 函数。我想他们最终会实现类似的目标。
  • 顺便说一下,你的get_fake_ptr()函数不需要定义。您可以简单地将其保留为template &lt;typename T&gt; T* get_fake_ptr();,您仍然可以在decltype 中使用它。
  • decltype(Ty::m_value) 有什么问题?
  • @bku_drytt std::declval&lt;&gt; 似乎是要走的路。你能写一个简短的答案让我接受吗?

标签: c++ c++11 c++14 decltype template-function


【解决方案1】:

您可以使用decltype(std::declval&lt;T&gt;().m_Value) 来推断Tm_Value 成员的类型,而不是使用您的get_fake_ptr() 函数。他们最终实现了相似的目标。

顺便说一句,您的get_fake_ptr() 函数不需要定义。您可以简单地将其保留为template &lt;typename T&gt; T* get_fake_ptr();,您仍然可以在decltype 中使用它。

【讨论】:

    【解决方案2】:

    我认为这种方法没有任何问题。

    当谈到模板元编程时,这些类型的“hacks”在课程中很常见。

    不过,我可以建议一种稍微不同的设计模式。像这样的:

    struct ClassInt
    {
        // Note: no default ctor
        ClassInt(int value)
            :   m_Value(value)
        {}
    
        typedef int m_value_t;
    
        m_value_t  m_Value;
    };
    
    struct ClassDouble
    {
        // Note: no default ctor
        ClassDouble(double value)
            :   m_Value(value)
        {}
    
        typedef double m_value_t;
    
        m_value_t  m_Value;
    };
    
    // ...
    template< typename Ty >
    void assign(std::string name, typename Ty::value_t value)
    {
        // Somehow get pointer to a Ty object by name
        Ty* obj = ????;
    
        // Assign
        obj->m_Value = value;
    }
    

    【讨论】:

      【解决方案3】:

      另一种选择是添加另一个模板参数,让赋值处理匹配类型和转换。任何不可转换的值类型都会产生编译错误。

      template<typename Ty, typename VALUE_TYPE>
      void assign(std::string name, VALUE_TYPE value) {
        Ty* obj = ???
        obj->m_Value = value;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-06-12
        • 1970-01-01
        • 1970-01-01
        • 2019-12-02
        • 2011-04-14
        • 1970-01-01
        • 2017-09-17
        相关资源
        最近更新 更多