我们说我们已经给出了模板实例化Container
(认为std::vector
是push_back
)和非模板类型T,我们需要检查我们是否可以在Container<T>
类型的对象上调用#include <iostream>
#include <vector>
#include <set>
#include <string>
#include <type_traits>
#include <boost/iterator.hpp>
#include <boost/range.hpp>
template<typename, typename>
struct replace
{
using type = struct Error;
};
template<template<typename...> class Container, typename U, typename T>
struct replace<Container<U>, T>
{
using type = Container<T>;
};
template<typename Container, typename T>
using replace_t = typename replace<Container, T>::type;
template<typename Placeholder, template<typename...> class Op, typename... Args>
struct isDetected : std::false_type {};
template<template<typename...> class Op, typename... Args>
struct isDetected<std::void_t<Op<Args...>>, Op, Args...> : std::true_type {};
template<typename Container, typename T>
using pushBackDetector = decltype(std::declval<Container&>().push_back(std::declval<T>()));
template<typename Container, typename T>
bool canPushBack()
{
return isDetected<void, pushBackDetector, Container, T> {};
}
int main()
{
std::cout << canPushBack<replace_t<std::vector<int>, double>, double>() << std::endl;
std::cout << canPushBack<replace_t<std::set<int>, double>, double>() << std::endl;
std::cout << canPushBack<replace_t<boost::iterator_range<std::string::iterator>, std::string::iterator>, double>() << std::endl;
//std::cout << canPushBack<replace_t<boost::iterator_range<std::string::iterator>, int>, double>() << std::endl;
}
。以下是使用检测器习语的代码:
push_back
Wandbox上的实例是available。
确实,它正确地推断我们可以在std::vector<double>
上调用std::set<double>
,但我们无法在boost::iterator_range<std::string::iterator>
或push_back
上执行此操作。
现在让我们检查一下我们是否可以在boost::iterator_range<int>
上拨打boost::iterator_range<int>
并取消注释最后一行!现在代码爆炸得非常漂亮,我不会在这里给出完整的错误消息(最好在上面链接的实例上做到这一点),但它的要点是编译器试图实例化/opt/wandbox/boost-1.65.1/clang-5.0.0/include/boost/iterator/iterator_categories.hpp:119:60: error: no type named 'iterator_category' in 'std::__1::iterator_traits<int>'
typename boost::detail::iterator_traits<Iterator>::iterator_category
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~
/opt/wandbox/boost-1.65.1/clang-5.0.0/include/boost/range/iterator_range_core.hpp:156:32: note: in instantiation of template class 'boost::iterators::iterator_traversal<int>' requested here
BOOST_DEDUCED_TYPENAME iterator_traversal<IteratorT>::type
^
/opt/wandbox/boost-1.65.1/clang-5.0.0/include/boost/range/iterator_range_core.hpp:436:67: note: in instantiation of template class 'boost::iterator_range_detail::pure_iterator_traversal<int>' requested here
BOOST_DEDUCED_TYPENAME iterator_range_detail::pure_iterator_traversal<IteratorT>::type
^
prog.cc:31:61: note: in instantiation of template class 'boost::iterator_range<int>' requested here
using pushBackDetector = decltype(std::declval<Container&>().push_back(std::declval<T>()));
^
prog.cc:28:31: note: in instantiation of template type alias 'pushBackDetector' requested here
struct isDetected<std::void_t<Op<Args...>>, Op, Args...> : std::true_type {};
^
prog.cc:36:12: note: during template argument deduction for class template partial specialization 'isDetected<std::void_t<Op<Args...> >, Op, Args...>' [with Op = pushBackDetector, Args = <boost::iterator_range<int>, double>]
return isDetected<void, pushBackDetector, Container, T> {};
^
和将失败的一些基本类型实例化为一个硬错误:
int
一方面,这很有道理 - 事实上,false
不是迭代器。另一方面,非常希望捕获这个不正确的实例化,并在这种情况下从canPushBack()
返回 select
`ACTUAL_TIME`,
`ACTUAL_DAY`,
`EXAMINED_AIRPORT_CODE`,
`EXAMINED_AIRPORT_AIRPORT`,
`EXAMINED_AIRPORT_COUNTRY`,
`ARRIVALS/DEPARTURES`,
`SCHEDULED_TIME`,
`FLIGHT`,
`FROM`,
`AIRLANE`,
`AIRCRAFT`,
`STATUS`,
`FLIGHT_ID_1`,
`FLIGHT_ID_2`,
`UPLOAD_TIME`
from OSSZES as a
left join (
select
`ACTUAL_TIME`
`ACTUAL_DAY`,
COALESCE(`EXAMINED_AIRPORT_CODE`, '') as EXAMINED_AIRPORT_CODE -- edit
`EXAMINED_AIRPORT_AIRPORT`,
`EXAMINED_AIRPORT_COUNTRY`,
`ARRIVALS/DEPARTURES`,
`SCHEDULED_TIME`,
`FLIGHT`,
`FROM`,
`AIRLANE`,
`AIRCRAFT`,
`STATUS`,
`FLIGHT_ID_1`,
`FLIGHT_ID_2`,
`UPLOAD_TIME`
from OSSZES_CLEAR
) as b using (`ACTUAL_DAY`,`EXAMINED_AIRPORT_CODE`,`FLIGHT`,`SCHEDULED_TIME`,`STATUS`)
where b.EXAMINED_AIRPORT_CODE is null
into outfile '/tmp/proba.csv'
fields terminated by ';'
enclosed by '"'
lines terminated by '\n';
。所以,这就是问题:是否有可能将这个硬错误变成软错误并优雅地处理它?</ p>
答案 0 :(得分:7)
不,您不能采用不支持SFINAE检测的模板,并且不需要针对相关类型的手动工作使SFINAE友好,有时候还不够。
你能做的最好的事情就是写一个为你做的手动特性,以及一个SFINAE检查是否可以应用的别名,如果可以的话只返回一个类型。
此外,检测某些东西是否为迭代器是不可能的。没有标准规定的SFINAE友好型&#34;是X迭代器&#34;试验。作为一般规则,所有迭代器都必须支持std::iterator_traits<T>
,但是有零要求非迭代器在将它们传递给std::iterator_traits
时必须生成SFINAE友好结果,并且我将void*
传递给std::iterator_traits
的经历会产生非SFINAE友好的结果。
您可以尝试破解一个 - 检测迭代器必须执行的各种事情(可解除引用,可递增,同等比较),但即使有类型在您尝试时也可能没有SFINAE友好错误。例如,采用非同等比较的类型并将其放在std::vector
中,并且尝试执行==
可能无法使用硬错误进行编译(至少上次检查时)。
一个简单的例子是:
template<class T>
struct problem {
static_assert(!std::is_same<T,int>{}, "oh oh");
};
将int
传递给problem
无法将SFINAE检测为问题。如果您实例化problem<int>
,则会出现硬错误。