C ++ 11:模板推导和const类型

时间:2014-04-08 23:29:22

标签: c++11

尝试使用完美转发,我遇到了模板扣除的问题。

以下编译

template<typename T>
void forwarder(T&& x)
{
}

int main()
{
    int x = 42;
    forwarder(x);
    return 0;
}

虽然如果我将const添加到模板化函数的签名中,则不会。

template<typename T>
void forwarder(const T&& x)  // adding const here
{
}

int main()
{
    int x = 42;
    forwarder(x);
    return 0;
}

来自g++

的错误消息
test.cc: In function ‘int main()’:
test.cc:11:16: error: cannot bind ‘int’ lvalue to ‘const int&&’
test.cc:4:6: error:   initializing argument 1 of ‘void forwarder(const T&&) [with T = int]’

我可以通过指定int&作为模板参数来实现它:forwarder<int&>(x)

我认为即使在模板中添加const也许会有用,但是在尝试了一些严重的失败之后我的头疼了。

对模板演绎有深刻理解的人能否告诉我这里发生了什么?使用带模板演绎的const是否可行且实用?

1 个答案:

答案 0 :(得分:0)

最好使用类型特征和标签分派来选择特定的过载:

template<typename T>
void forwarder_impl(T&& x, std::true_type, std::true_type)
{
    std::cout << "rvalue reference to const\n";
}
template<typename T>
void forwarder_impl(T&& x, std::true_type, std::false_type)
{
    std::cout << "rvalue reference to non-const\n";
}
template<typename T>
void forwarder_impl(T&& x, std::false_type, std::true_type)
{
    std::cout << "lvalue reference to const\n";
}
template<typename T>
void forwarder_impl(T&& x, std::false_type, std::false_type)
{
    std::cout << "lvalue reference to non-const\n";
}

template<typename T>
void forwarder(T&& x)
{
    forwarder_impl(
        std::forward<T>(x),
        typename std::is_rvalue_reference<decltype(x)>::type(),
        typename std::is_const<typename std::remove_reference<decltype(x)>::type>::type()
    );
}

int main()
{
    const int x = 42;
    int y = 42;
    forwarder(std::move(x));
    forwarder(std::move(y));
    forwarder(x);
    forwarder(y);
}

输出:

rvalue reference to const
rvalue reference to non-const
lvalue reference to const
lvalue reference to non-const

实例:http://ideone.com/vHZ7oC

为什么你想做到这一点仍然是一个谜。


如果您想限制forwarder仅接受对const的引用,您可以使用SFINAE来保留T&&的普遍性:

template<typename T>
typename std::enable_if<
    std::is_const<typename std::remove_reference<T>::type>::value
>::type
forwarder(T&& x)
{
    auto value_cat = std::is_rvalue_reference<decltype(x)>::value ? "r" : "l";
    std::cout << value_cat << "value reference to const\n";
}

int main()
{
    const int x = 42;
    forwarder(std::move(x));
    forwarder(x);
    //int y = 42;
    //forwarder(std::move(y));  //compile-time error
    //forwarder(y);             //compile-time error
}

输出:

rvalue reference to const
lvalue reference to const

http://ideone.com/t5UoZE http://ideone.com/jc2Ek2

再一次,这种事情的动机超出了我的范围。


资源:https://www.google.com/search?q=scott+meyers+universal+references