【问题标题】:Universal reference for a concrete type [duplicate]具体类型的通用参考[重复]
【发布时间】:2014-12-31 19:13:08
【问题描述】:

我希望一个函数具有一个具有具体类型的通用引用参数。我希望它是通用引用,这样当我对检查其中存储的值不感兴趣时​​,我可以传递一个临时对象。

示例如下:

bool bCompareData(const uint8_t *arg_0, const uint8_t *arg_1, size_t &szComparedData)
{
    size_t &i = szComparedData;

    for (; arg_1[i]; ++i)
        if (arg_1[i] != arg_0[i])
            return false;

    return true;
}

以及可能的函数调用:

bCompareData(Obj.uIdObject.data(), Ref.uIdTargetObject.data(), size_t()) // here we are passing a temporary (rvalue)
/*________________________*/ 
size_t lval;
bCompareData(Obj.uIdObject.data(), Ref.uIdTargetObject.data(), lval) // here we are passing a named variable (lvalue)

在第一个函数调用编译器中使用上述函数声明会出错,如果我将“size_t &szComparedData”更改为右值引用“size_t &&szComparedData”,第二次调用将失败。

现在我需要的是通用引用,但我也想在我的论点上有一个具体的类型,而不是使用模板。

我正在使用 VC++ U3 2013 编译器。

【问题讨论】:

  • MSVC 不允许第一个吗? (将非常量引用绑定到临时)
  • 这里的另一种选择是将其设为 size_t * ,然后如果您对查看结果不感兴趣,则可以传递 nullptr (这可能是默认值)
  • 顺便说一句,你的实现很奇怪。看来您想要strcmpmemcmpstd::mismatch
  • @FrançoisMoisan:从示例中,参数既用作输入也用作输出。

标签: c++


【解决方案1】:

通用引用仅适用于定义的模板和类型推导。您只能使用 SFINAE 将引用限制为特定类型:

template< typename S >
typename std::enable_if<
    std::is_same<typename std::decay<S>::type,size_t>::value,
bool>::type
bCompareData(const uint8_t *arg_0, const uint8_t *arg_1, S&& szComparedData)
{
    // ...
}

或者,如果您真的需要避免使用模板,则需要重载方法:

bool bCompareData(const uint8_t *arg_0, const uint8_t *arg_1, size_t& szComparedData)
{
    // ...
}

bool bCompareData(const uint8_t *arg_0, const uint8_t *arg_1, size_t&& szComparedData)
{
    // ...
}

【讨论】:

  • 函数修改了输入,所以匹配const size_t变量会出错。 (此外,我认为您的重载会产生歧义)
  • 你的重载版本不起作用,因为函数修改了左值
  • @MooingDuck 是的,但A&amp;A&amp;&amp; 是否明确且适用于所有情况?但也许在这里没关系,因为问题确实将其限制为可修改或临时值,不包括常量值。不寻常但可能。
  • @DanielFrey:是的,A&amp;A&amp;&amp; 是明确的;造成歧义的是const&amp;&amp;&amp;,它们都接受临时的。
  • @MooingDuck D'oh,当然。谢谢。 (并为您的回答 +1)
【解决方案2】:

不能有一个通用引用而不使用模板,因为“通用引用”是一个模板的东西。您想要的是能够传递左值或右值,这可以在没有模板的情况下完成。

这里正确的工具是重载。有趣的是,这只需要一个非常简单的重载。

bool bCompareData(const uint8_t *arg_0, const uint8_t *arg_1, size_t &szComparedData)
{
    size_t &i = szComparedData;

    for (; arg_1[i]; ++i)
        if (arg_1[i] != arg_0[i])
            return false;

    return true;
}
bool bCompareData(const uint8_t *arg_0, const uint8_t *arg_1, size_t &&szComparedData)
{ return bCompareData(arg_0, arg_1, szComparedData);}

这是可行的,因为函数参数列表中的&amp;&amp; 告诉该函数参数是从右值构造,但所有命名值本身都是左值。因为它有名字,所以它是一个左值,你可以简单地将它传递给现有的函数。

【讨论】:

  • 都不匹配const size_t变量
  • @PiotrS.:函数修改了输入,所以匹配const size_t变量会出错。
【解决方案3】:

或者我后来做了什么,我认为这不是最好的解决方案:

template <typename T = size_t>

inline bool bCompareData(const uint8_t *arg_0, const uint8_t *arg_1, T &&arg_2 = size_t())
{
    arg_2 = 0;

    extern bool _bCompareData(const uint8_t *, const uint8_t *, size_t &); //compare data

    return _bCompareData(arg_0, arg_1, arg_2);
}

C++ 是一种非常奇怪的语言。我的意思是“右值”和“左值”引用都具有相同的大小和属性,所以它们是如何变成不同类型的。

【讨论】:

  • 它不需要模板,但这是解决问题的一种方法。
  • 左值和右值不具有相同的属性。例如,右值不能分配给可变引用,也不能通过可变引用传递。 char[12]std::vector&lt;std::string&gt; 有时可能具有相同的大小,但很难将它们称为同一类型。
猜你喜欢
  • 2017-12-31
  • 1970-01-01
  • 2013-12-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多