olp*_*lpa 5 c++ template-meta-programming c++11
Stroustrup的书提供了一个如何回答这个问题的例子:" f(x)如果x是类型的话,是否可以调用X"(第28.4.4节"使用Enable_if的更多示例").我试图重现这个例子,但是出了点问题,无法理解.
在我的下面的代码中,有一个函数f(int).我希望那时的结果has_f<int>::value是1(true).实际结果是0(false).
#include <type_traits>
#include <iostream>
//
// Meta if/then/else specialization
//
struct substitution_failure { };
template<typename T>
struct substitution_succeeded : std::true_type { };
template<>
struct substitution_succeeded<substitution_failure> : std::false_type { };
//
// sfinae to derive the specialization
//
template<typename T>
struct get_f_result {
private:
template<typename X>
static auto check(X const& x) -> decltype(f(x));
static substitution_failure check(...);
public:
using type = decltype(check(std::declval<T>()));
};
//
// has_f uses the derived specialization
//
template<typename T>
struct has_f : substitution_succeeded<typename get_f_result<T>::type> { };
//
// We will check if this function call be called,
// once with "char*" and once with "int".
//
int f(int i) {
std::cout << i;
return i;
}
int main() {
auto b1{has_f<char*>::value};
std::cout << "test(char*) gives: " << b1 << std::endl;
std::cout << "Just to make sure we can call f(int): ";
f(777);
std::cout << std::endl;
auto b2{has_f<int>::value};
std::cout << "test(int) gives: " << b2 << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
输出:
test(char*) gives: 0
Just to make sure we can call f(int): 777
test(int) gives: 0
Run Code Online (Sandbox Code Playgroud)
主要问题是你在f这里打了一个不合格的电话:
template<typename X>
static auto check(X const& x) -> decltype(f(x));
Run Code Online (Sandbox Code Playgroud)
f将要找到的s将是check()(none)定义范围内的那些,以及通过相关命名空间中的参数依赖查找找到的那些X.由于XIS int,它有没有相关的命名空间,你会发现没有f在那儿任.由于ADL永远不会起作用int,因此必须在get_f_result定义之前显示您的函数.只需将其向上移动就可以解决这个问题.
现在,你has_f过于复杂了.substitution_succeeded机器没有理由.只需让两个check()重载返回你想要的类型:
template<typename T>
struct has_f {
private:
template <typename X>
static auto check(X const& x)
-> decltype(f(x), std::true_type{});
static std::false_type check(...);
public:
using type = decltype(check(std::declval<T>()));
};
Run Code Online (Sandbox Code Playgroud)
现在has_f<T>::type已经是true_type或者false_type.
当然,即使这样也过于复杂.检查表达式是否有效是一个相当常见的操作,因此简化它是有帮助的(从Yakk借来,类似于std::is_detected):
namespace impl {
template <template <class...> class, class, class... >
struct can_apply : std::false_type { };
template <template <class...> class Z, class... Ts>
struct can_apply<Z, std::void_t<Z<Ts...>>, Ts...> : std::true_type { };
};
template <template <class... > class Z, class... Ts>
using can_apply = impl::can_apply<Z, void, Ts...>;
Run Code Online (Sandbox Code Playgroud)
这是你写的:
template <class T>
using result_of_f = decltype(f(std::declval<T>()));
template <class T>
using has_f = can_apply<result_of_f, T>;
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
265 次 |
| 最近记录: |