【问题标题】:Select function based on if template is pointer/reference or none根据模板是指针/引用还是无选择函数
【发布时间】:2018-11-28 16:17:16
【问题描述】:

我想根据函数是指针、引用还是常规类型来提供不同的函数实现。到目前为止,这是我的代码:

template<class T,
         class = typename std::enable_if_t<std::is_reference<T>::value>>
void f(T && in)
{}

// This causes redefinition error 
template<class T,
    class = typename std::enable_if_t<std::is_pointer<T>::value>>
void f(T && in)
{}

template<class T,
    class = typename std::enable_if_t<!std::is_reference<T>::value>,
    class = typename std::enable_if_t<!std::is_pointer<T>::value>>
void f(T && in)
{}

中间函数原因:

12:13:错误:'template void f(T&&)'的重新定义

7:13:注意:'template void f(T&&)' 先前声明 这里

有趣的是只有第一个和最后一个函数一起编译。

关于如何修复它或简化此代码的任何想法。

【问题讨论】:

  • 默认模板参数不是模板签名的一部分。所以这 3 个模板中,前两个具有相同的签名,而第三个采用 3 个模板参数。
  • 为什么不只是重载void f(T*)void f(T&amp;)void f(T)
  • @NathanOliver:我如何将void f(T&amp;&amp;) 作为不转发参考?我的意思是我可以把整个过程倒过来,但不确定它是否会让事情变得更容易。
  • @AndreasPasternak 查看皮特·贝克尔的回答
  • @NathanOliver:你是对的!

标签: c++ c++11 sfinae


【解决方案1】:

通常的方法是提供适当的重载:

#include <iostream>

template <class T> void f(T&&) {
    std::cout << "T&&\n";
}

template <class T> void f(T*) {
    std::cout << "T*\n";
}

template <class T> void f(T&) {
    std::cout << "T&\n";
}

int main() {
    int i;
    f(std::move(i));
    f(&i);
    f(i);
}

这会产生以下输出:

[temp]$ clang++ -std=c++11 test.cpp
[temp]$ ./a.out
T&&
T*
T&
[temp]$ 

【讨论】:

  • 如何处理 const 引用和指针?我是否也不需要额外的超载?
  • @AndreasPasternak -- 你需要重载你想要区分的任何类型。此答案解决了您在问题和代码中提到的类型。
【解决方案2】:

模板默认参数值不是签名的一部分,因此您需要通过添加额外的虚拟模板参数来进一步消除重载的歧义 - 例如 - 添加一个额外的虚拟模板参数:

template<class T,
         class = typename std::enable_if_t<std::is_reference<T>::value>>
void f(T && in)
{}

// This causes redefinition error 
template<class T,
    class = typename std::enable_if_t<std::is_pointer<T>::value>, class = void>
void f(T && in)
{}

【讨论】:

  • 太好了,编译成功了。如果它也按预期工作,我会接受。到目前为止,谢谢!
猜你喜欢
  • 1970-01-01
  • 2014-04-19
  • 2015-08-13
  • 2016-12-24
  • 1970-01-01
  • 1970-01-01
  • 2010-12-11
  • 2017-09-27
  • 1970-01-01
相关资源
最近更新 更多