以下特征类用于检查通用 vector 是否具有operator[](int)
或operator()(int)
:
template<typename ...> using void_t = void;
template< typename, typename = void>
struct has_bracket_operator : public std::false_type {};
template<typename V>
struct has_bracket_operator<V, void_t<decltype(std::declval<V>()[int{}])> >
: public std::true_type{};
template<typename, typename = void>
struct has_parenthesis_operator : public std::false_type {};
template<typename V>
struct has_parenthesis_operator<V, void_t<decltype(std::declval<V>()(int{}))> >
: public std::true_type{};
另一方面,在最新的 MSVC 下载(Microsoft Visual Studio Community 2015 RC 版本 14.0.22823.1 D14REL)中,has_parenthesis_operator
模板出现编译错误内容如下:
error C2064: term does not evaluate to a function taking 1 arguments
此外,我发现以下版本更可取,两者都根本不编译(请注意,使用 operator[](int{})
而不是 [int{}]
,和括号类似):
template<typename V>
struct has_bracket_operator<V, void_t<decltype(std::declval<V>().operator[](int{}))> >
: public std::true_type{};
//...
template<typename V>
struct has_parenthesis_operator<V, void_t<decltype(std::declval<V>().operator()(int{}))> >
: public std::true_type{};
这里的错误信息是
error C2228: left of '.[]' must have class/struct/union note: type is 'add_rvalue_reference<V>::type' error C2228: left of '.()' must have class/struct/union note: type is 'add_rvalue_reference<V>::type'
问题:
- 这是一个错误吗?还是我做错了什么(gcc 以某种方式接受)?
- 是否有一种解决方法可以让我使用上述技术(特别是
void_t
) - 如果无法解决,如何在 MSVC 中设置备用 SFINAE 检查(我尝试了很多 this 但没有真正成功 -- 至少在 MSVC 中)?
最佳答案
如@T.C. 所述,上述方法通过 void_t<decltype(...)>
需要 expression SFINAE , 这在当前版本的 MSVC 2015 中不可用。
这是表达 SFINAE 的当前状态,取自 here :
Q. When will you implement Expression SFINAE?
A. We're planning to start implementing Expression SFINAE in the compiler immediately after 2015 RTM, and we're planning to deliver it in an Update to 2015, supported for production use. (But not necessarily 2015 Update 1. It might take longer.)
To be extra clear, this applies to the compiler only, not the libraries. The C++11 Standard Library mandated the use of Expression SFINAE in a small number of places, which we've actually already implemented. (The places are is_assignable and allocator_traits, which the compiler has taken special care to support.) The C++14 Standard Library added two more places where Expression SFINAE must be used: std::function construction/assignment and result_of. I'll modify the STL when the compiler is ready, but I'm not planning to ship those library changes in an Update. ...
此外,这里有一个有点使用传统 SFINAE 解决上述特征的更老式的解决方法(灵感来自 here ):
template<typename C, typename Ret, typename... Args>
struct has_parenthesis_operator<C, Ret(Args...)>
{
private:
template<typename T>
static constexpr auto check(T*)
-> typename std::is_same<std::decay_t<decltype(std::declval<T>().operator()(std::declval<Args>()...))>, Ret>::type;
template<typename> static constexpr std::false_type check(...);
typedef decltype(check<C>(0)) type;
public:
static constexpr bool value = type::value;
};
可以用作例如
template<typename V
, typename = std::enable_if_t<has_bracket_operator<V, double(int)>::value>
auto get(V const& v, int i)
{
return v[i];
}
这会检查传递的 vector 类型是否有成员 double operator[](int)
, 如果这样调用它(——否则可以用括号运算符做类似的事情)。
关注@Yakk 的评论:我遇到了 __if_exists
statement MSVC 的特殊功能,它似乎完成了与上述类似的任务。
关于C++ traits类检测成员函数: compiler error in MSVC 2015 RC,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30856989/