【问题标题】:Function template specialization and rvalue reference in c++c++中的函数模板特化和右值引用
【发布时间】:2015-04-21 09:01:13
【问题描述】:
    #include <iostream>

    struct Cls{double dval = 0;};

    template<typename T>
    void foo(T&& Obj) {
        //..... use Obj
    } 

    void foo(const Cls& Obj) {
        //..... use Obj.dval
    }

    //void foo(Cls Obj) {
    //    //..... use Obj.dval
    //}

    int main()
    {
        Cls Obj;
        const Cls cv_Obj;

        foo(Obj); //case 1
        foo(Cls{}); //case 2
        foo(cv_Obj); //case 3
        foo(10.10);
    }

如果函数参数为 const refby val 适用于所有情况,则 Cls 的模板特化失败 (case 1, case 2)。

除了pass by val,还有其他方法可以处理所有cases(所有值类型)的特化吗?

【问题讨论】:

  • 您的模板版本中的行肯定应该是std::cout&lt;&lt;Obj.dval; 而不是std::cout&lt;&lt;Obj;
  • 下划线开头的标识符保留在全局命名空间中。
  • fails 是什么意思?你看到了什么错误?
  • 我想用foo打印double, int, etc...,所以模板必须是std::cout&lt;&lt;Obj;错误:除了foo(cv_Obj);,调用了void foo(T&amp;&amp; Obj)函数。 error: no match for 'operator&lt;&lt;' (operand types are 'std::ostream {aka std::basic_ostream&lt;char&gt;}' and '_struct')
  • 也与 const-default 构造函数问题有关 stackoverflow.com/questions/26077807/…

标签: c++ templates template-specialization


【解决方案1】:

您可以使用 SFINAE 解决此问题,但摆脱 _struct 上的重载并为 operator&lt;&lt; 定义重载会容易得多:

std::ostream& operator<<(std::ostream& os, const _struct& obj)
{
  os << obj.dval;
  return os;
}

使用 SFINAE 解决的一种可能性是在一个重载中直接检查输出 Obj 的有效性,并在另一个重载中检查 _struct 的类型:

template<typename T>
auto foo(T&& Obj) -> decltype(std::cout<<Obj, void()) {
    std::cout<<Obj;
}

template<typename T, 
         std::enable_if_t<std::is_same<_struct, std::decay_t<T>>::value>* = nullptr>
void foo(T&& Obj) {
    std::cout<<Obj.dval;
} 

【讨论】:

  • 这是expression SFINAE。本质上,如果该 decltype 中的表达式格式不正确,则该重载将从候选集中清除,而不是导致硬错误。
【解决方案2】:

你需要一个辅助结构:

#include <iostream>

struct _struct{double dval = 0;};

template<typename T, typename Enable = void>
struct bar {
    bar(T&& Obj) {
        std::cout<<Obj;
    }
};

template<typename T>
struct bar<T, typename std::enable_if<std::is_same<typename std::decay<T>::type, _struct>::value>::type> {
    bar(T&& Obj) {
        std::cout<<Obj.dval;
    }
};

template<typename T>
void foo(T&& Obj) {
    bar<T>(std::forward<T>(Obj));
}

int main()
{
    _struct Obj;
    const _struct cv_Obj;

    foo(1);
    foo(Obj); //case 1
    foo(_struct{}); //case 2
    foo(cv_Obj); //case 3
    foo("test");
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-08-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多