Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/145.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 2013年VSINAE_C++_Visual Studio_C++11 - Fatal编程技术网

C++ 2013年VSINAE

C++ 2013年VSINAE,c++,visual-studio,c++11,C++,Visual Studio,C++11,我有一个函数模板forwardMaybeNull。如果第一个参数不是nullptr,我希望它可以转发第一个参数,如果第一个参数是nullptr,则只返回第二个参数 template <typename T, typename U, std::enable_if_t<std::is_same<T, std::nullptr_t>::value>...> U&& forwardMaybeNull(std::nullptr_t,

我有一个函数模板
forwardMaybeNull
。如果第一个参数不是
nullptr
,我希望它可以转发第一个参数,如果第一个参数是
nullptr
,则只返回第二个参数

template <typename T, typename U,
          std::enable_if_t<std::is_same<T, std::nullptr_t>::value>...>
U&& forwardMaybeNull(std::nullptr_t, U&& rvalue_default) {
  return std::move(rvalue_default);
}

template <typename T, typename U,
          std::enable_if_t<!std::is_same<T, std::nullptr_t>::value>...>
T&& forwardMaybeNull(std::remove_reference_t<T>& arg, U&&) {
  return static_cast<T&&>(arg);
}

template <typename T, typename U,
          std::enable_if_t<!std::is_same<T, std::nullptr_t>::value>...>
T&& forwardMaybeNull(std::remove_reference_t<T>&& arg, U&&) {
  return static_cast<T&&>(arg);
}

template <typename T>
void Bar(T&&) {}

template <typename T>
void Foo(T&& t) {
    Bar(forwardMaybeNull<T>(t, [](){}));
}

int main() {
  Foo(nullptr);
}
模板
U&&forwardMaybeNull(标准::nullptr\U t,U&&rvalue\U默认值){
返回std::move(右值默认值);
}
模板…>
T&&forwardMaybeNull(标准::删除\U参考\U T&arg,U&&){
返回静态_cast(arg);
}
模板…>
T&&forwardMaybeNull(标准::删除\U引用\U T&&arg,U&&){
返回静态_cast(arg);
}
模板
空条(T&&{}
模板
无效Foo(T&T){
Bar(前向maybenull(t,[](){}));
}
int main(){
Foo(nullptr);
}

它在gcc4.8中运行良好,但VS2013说它是“对重载函数的不明确调用”。

我建议避免在VS2013中使用任何不重要的模板代码。见鬼,即使是我称之为琐碎的模板代码也给我带来了麻烦

对于这种情况,您可以求助于旧技术,部分专门化类模板。即使在GCC中,我也会这样做。类似下面的内容

namespace detail {

template <typename T, typename U>
struct forwarderMaybeNull {
  using result_type = T&&;
  static T&& call(std::remove_reference_t<T>& arg, U&&) {
    return static_cast<T&&>(arg);
  }

  static T&& call(std::remove_reference_t<T>&& arg, U&&) {
    return static_cast<T&&>(arg);
  }
};

template <typename U>
struct forwarderMaybeNull<nullptr_t, U> {
  using result_type = U&&;
  static U&& call(std::nullptr_t, U&& rvalue_default) {
    return std::move(rvalue_default);
  }
};

}

template <typename T, typename U>
typename detail::forwarderMaybeNull<T, U>::result_type forwardMaybeNull(
    std::remove_reference_t<T>& arg, U&& u) {
  return detail::forwarderMaybeNull<T, U>::call(std::forward<T>(arg),
                                                std::forward<U>(u));
}
template <typename T, typename U>
typename detail::forwarderMaybeNull<T, U>::result_type forwardMaybeNull(
    std::remove_reference_t<T>&& arg, U&& u) {
  return detail::forwarderMaybeNull<T, U>::call(std::forward<T>(arg),
                                                std::forward<U>(u));
}
名称空间详细信息{
模板
结构转发程序{
使用结果_type=T&;
静态T&&call(std::remove_reference_T&arg,U&&){
返回静态_cast(arg);
}
静态T&&call(std::remove_reference_T&&arg,U&&){
返回静态_cast(arg);
}
};
模板
结构转发程序{
使用结果_type=U&;
静态U&&call(std::nullptr\U t、U&&rvalue\U默认值){
返回std::move(右值默认值);
}
};
}
模板
typename详细信息::forwarderMaybeNull::结果\类型forwardMaybeNull(
标准::删除\U引用\U t&arg、U&U){
返回详细信息::ForwarderMyBenull::调用(std::forward(arg),
标准:正向(u));
}
模板
typename详细信息::forwarderMaybeNull::结果\类型forwardMaybeNull(
标准::删除\U引用\U t&&arg,U&&U){
返回详细信息::ForwarderMyBenull::调用(std::forward(arg),
标准:正向(u));
}

我认为问题是由于这个错误造成的。如果使用enable_If而不是enable_If,它应该可以工作。对于函数模板中的SFINAE,通常最好使用未命名的默认模板参数,而不是变量包

我在MSVC2013更新2中大量使用了此模式,但没有出现任何实际问题:

template <typename T, typename U, typename = typename std::enable_if<std::is_same<
    T, std::nullptr_t>::value>::type>
U&& forwardMaybeNull(std::nullptr_t, U&& rvalue_default) {
  return std::move(rvalue_default);
}
模板::类型>
U&&forwardMaybeNull(标准::nullptr\U t,U&&rvalue\U默认值){
返回std::move(右值默认值);
}
尽管在MSVC2013更新3中修复了有问题的别名错误,但它们基本上破坏了初始值设定项列表(),因此升级可能不是一个好主意

在这种情况下,我建议使用标记分派而不是SFINAE来实现静态分派:

template <typename T, typename U>
U&& forwardMaybeNull(std::true_type, T, U&& rvalue_default) {
  return std::move(rvalue_default);
}

template <typename T, typename U>
T&& forwardMaybeNull(std::false_type,T&& arg, U&&) {
  return std::forward<T>(arg);
}

template <typename T>. 
void Foo(T&& t) {
    Bar(forwardMaybeNull(typename std::is_same<T, std::nullptr_t>::type{}, std::forward<T>(t), [](){}));
}
模板
U&&forwardMaybeNull(标准::true_类型,T,U&&rvalue_默认值){
返回std::move(右值默认值);
}
模板
T&&forwardMaybeNull(标准::false_类型,T&&arg,U&&){
返回标准::转发(arg);
}
模板。
无效Foo(T&T){
Bar(forwardMaybeNull(typename std::is_same::type{},std::forward(t),[](){});
}

我的建议是在VS2013中尽可能避免使用SFINAE,或者最好尽可能避免使用VS2013。这是一个痛苦的世界。已经超过了SFINAE的标准。可变无效包真的是获得SFINAE的合法方法吗?1)你的第三个转发包可能是第二个转发包的精确副本。2) 使用
typename=std::enable_if_t::value>
而不是
std::enable_if_t::value>。
3)利润(VS2013更新2)4)注意enable_if_t和SFINAE()新引入的错误谢谢您的评论。1) 第二个
forwardMaybeNull
采用左值引用,而第三个采用右值引用。2) @QingYun 1)哦,我没有注意到,对不起2)我在Scott Meyers的博客中看到了这篇文章的链接,但遗憾的是,它在VSIt中无法正常工作。对于左值引用和右值引用,似乎仍然需要重载,就像
std::forward
一样。或者显式地
std::forward
forwardMaybeNull的参数,比如
forwardMaybeNull(std::forward(t),[](){})
.Hmm,这是真的。我应该把它修好。