gpt4 book ai didi

c++ - SFINAE 未能处理中间类型特征

转载 作者:行者123 更新时间:2023-11-30 00:43:52 24 4
gpt4 key购买 nike

考虑以下测试代码:

// Preprocessor
#include <iostream>
#include <type_traits>

// Structure with no type alias
template <class T>
struct invalid {
};

// Structure with a type alias
template <class T>
struct valid {
using type = T;
};

// Traits getting the type of the first type
template <class T, class... Args>
struct traits {
using type = typename T::type;
};

// One argument function
template <class T, class = typename traits<T>::type>
void function(T) {
std::cout << "function(T)" << std::endl;
}

// Two arguments function
template <class T, class U, class = typename traits<T, U>::type>
void function(T, U) {
std::cout << "function(T, U)" << std::endl;
}

// When function can be called on all arguments
template <
class... Args,
class = decltype(function(std::declval<Args>()...))
>
void sfinae(Args&&... args) {
function(std::forward<Args>(args)...);
std::cout << "sfinae(Args&&...)" << std::endl;
}

// When function can be called on all arguments except the first one
template <
class T,
class... Args,
class = decltype(function(std::declval<Args>()...))
>
void sfinae(const invalid<T>&, Args&&... args) {
function(std::forward<Args>(args)...);
std::cout << "sfinae(const invalid<T>&, Args&&...)" << std::endl;
}

// Main function
int main(int argc, char* argv[]) {
valid<int> v;
invalid<int> i;
sfinae(v);
sfinae(i, v);
return 0;
}

代码涉及:

  • 结构invalid没有 ::type
  • 结构valid有一个::type
  • 结构traits定义 ::type作为T::type
  • 重载function仅当第一个参数的类型为 traits<T>::type 时才有效定义
  • 重载sfinae应该能够调用 function 的函数即使第一个参数是 invalid

但是,SFINAE 机制在这种情况下似乎不起作用,我不确定为什么。错误如下:

sfinae_problem_make.cpp:19:30: error: no type named 'type' in 'invalid<int>'
using type = typename T::type;
~~~~~~~~~~~~^~~~
sfinae_problem_make.cpp:29:46: note: in instantiation of template class 'traits<invalid<int>, valid<int> >' requested here
template <class T, class U, class = typename traits<T, U>::type>
^
sfinae_problem_make.cpp:30:6: note: in instantiation of default argument for 'function<invalid<int>, valid<int> >' required here
void function(T, U) {
^~~~~~~~~~~~~~~~
sfinae_problem_make.cpp:37:22: note: while substituting deduced template arguments into function template 'function' [with T = invalid<int>, U = valid<int>, $2 = (no value)]
class = decltype(function(std::declval<Args>()...))
^
sfinae_problem_make.cpp:39:6: note: in instantiation of default argument for 'sfinae<invalid<int> &, valid<int> &>' required here
void sfinae(Args&&... args) {
^~~~~~~~~~~~~~~~~~~~~~~~
sfinae_problem_make.cpp:60:5: note: while substituting deduced template arguments into function template 'sfinae' [with Args = <invalid<int> &, valid<int> &>, $1 = (no value)]
sfinae(i, v);

非常令人惊讶的是,如果从问题中删除特征:

// Preprocessor
#include <iostream>
#include <type_traits>

// Structure with no type alias
template <class T>
struct invalid {
};

// Structure with a type alias
template <class T>
struct valid {
using type = T;
};

// Traits getting the type of the first type
template <class T, class... Args>
struct traits {
using type = typename T::type;
};

// One argument function
template <class T, class = typename T::type>
void function(T) {
std::cout << "function(T)" << std::endl;
}

// Two arguments function
template <class T, class U, class = typename T::type>
void function(T, U) {
std::cout << "function(T, U)" << std::endl;
}

// When function can be called on all arguments
template <
class... Args,
class = decltype(function(std::declval<Args>()...))
>
void sfinae(Args&&... args) {
function(std::forward<Args>(args)...);
std::cout << "sfinae(Args&&...)" << std::endl;
}

// When function can be called on all arguments except the first one
template <
class T,
class... Args,
class = decltype(function(std::declval<Args>()...))
>
void sfinae(const invalid<T>&, Args&&... args) {
function(std::forward<Args>(args)...);
std::cout << "sfinae(const invalid<T>&, Args&&...)" << std::endl;
}

// Main function
int main(int argc, char* argv[]) {
valid<int> v;
invalid<int> i;
sfinae(v);
sfinae(i, v);
return 0;
}

然后它按预期工作并输出:

function(T)
sfinae(Args&&...)
function(T)
sfinae(const invalid<T>&, Args&&...)

问题:为什么第一个版本不起作用,有没有办法让它与中间类型特征一起工作?

最佳答案

SFINAE 要求替换失败发生在实例化的“直接上下文中”。否则会出现硬错误。

没有中间体traits类型,function<invalid<int>, valid<int>, invalid<int>::type> 的实例化因为 invalid<int> 在直接上下文中导致错误没有名为 type 的成员, 所以 SFINAE 开始了。

与中间体traits类型,错误发生在定义的实例化过程中 traits<invalid<int>>因为这需要不存在的 invalid<int>::type .这不在直接上下文中,因此会发生硬错误。

要解决此问题,您必须确保 traits总是有一个有效的定义。这可以像这样完成:

template <class T, class = void>
struct traits {};

template <class T>
struct traits<T, std::void_t<typename T::type>> {
using type = typename T::type;
};

关于c++ - SFINAE 未能处理中间类型特征,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52082069/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com