C++ 使用 enable_if 检查成员是否存在
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13786888/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
check if member exists using enable_if
提问by bobobobo
Here's what I'm trying to do:
这是我想要做的:
template <typename T> struct Model
{
vector<T> vertices ;
#if T has a .normal member
void transform( Matrix m )
{
each vertex in vertices
{
vertex.pos = m * vertex.pos ;
vertex.normal = m * vertex.normal ;
}
}
#endif
#if T has NO .normal member
void transform( Matrix m )
{
each vertex in vertices
{
vertex.pos = m * vertex.pos ;
}
}
#endif
} ;
I've seen examplesof using enable_if
, but I cannot understand how to apply enable_if
to this problem, or if it even can be applied.
我看过使用 的例子enable_if
,但我不明白如何应用enable_if
这个问题,或者它是否可以应用。
采纳答案by Johannes Schaub - litb
This has become wayeasier with C++11.
这已经成为这样更容易与C ++ 11。
template <typename T> struct Model
{
vector<T> vertices;
void transform( Matrix m )
{
for(auto &&vertex : vertices)
{
vertex.pos = m * vertex.pos;
modifyNormal(vertex, m, special_());
}
}
private:
struct general_ {};
struct special_ : general_ {};
template<typename> struct int_ { typedef int type; };
template<typename Lhs, typename Rhs,
typename int_<decltype(Lhs::normal)>::type = 0>
void modifyNormal(Lhs &&lhs, Rhs &&rhs, special_) {
lhs.normal = rhs * lhs.normal;
}
template<typename Lhs, typename Rhs>
void modifyNormal(Lhs &&lhs, Rhs &&rhs, general_) {
// do nothing
}
};
Things to note:
注意事项:
- You can name non-static data members in
decltype
andsizeof
without needing an object. - You can apply extended SFINAE. Basically any expression can be checked and if it is not valid when the arguments are substituted, the template is ignored.
- 您可以命名在非静态数据成员
decltype
和sizeof
不需要的对象。 - 您可以申请扩展的 SFINAE。基本上可以检查任何表达式,如果在替换参数时它无效,则忽略模板。
回答by ltjax
You need a meta function to detect your member so that you can use enable_if
. The idiom to do this is called Member Detector. It's a bit tricky, but it can be done!
您需要一个元函数来检测您的成员,以便您可以使用enable_if
. 这样做的习惯用法称为Member Detector。这有点棘手,但它可以做到!
回答by NutCracker
I know this question already has some answers but I think my solution to this problem is a bit different and could help someone.
我知道这个问题已经有了一些答案,但我认为我对这个问题的解决方案有点不同,可以帮助某人。
The following example checks whether passed type contains c_str()
function member:
以下示例检查传递的类型是否包含c_str()
函数成员:
template <typename, typename = void>
struct has_c_str : false_type {};
template <typename T>
struct has_c_str<T, void_t<decltype(&T::c_str)>> : std::is_same<char const*, decltype(declval<T>().c_str())>
{};
template <typename StringType,
typename std::enable_if<has_c_str<StringType>::value, StringType>::type* = nullptr>
bool setByString(StringType const& value) {
// use value.c_str()
}
In case there is a need to perform checks whether passed type contains specific data member, following can be used:
如果需要检查传递的类型是否包含特定的数据成员,可以使用以下方法:
template <typename, typename = void>
struct has_field : std::false_type {};
template <typename T>
struct has_field<T, std::void_t<decltype(T::field)>> : std::is_convertible<decltype(T::field), long>
{};
template <typename T,
typename std::enable_if<has_field<T>::value, T>::type* = nullptr>
void fun(T const& value) {
// use value.field ...
}
UPDATE C++20
更新 C++20
C++20 introduced constraints and concepts, core language features in this C++ version.
C++20 在这个 C++ 版本中引入了约束和概念,核心语言特性。
If we want to check whether template parameter contains c_str
member function, then, the following will do the work:
如果我们要检查模板参数是否包含c_str
成员函数,那么,以下将完成工作:
template<typename T>
concept HasCStr = requires(T t) { t.c_str(); };
template <HasCStr StringType>
void setByString(StringType const& value) {
// use value.c_str()
}
Furthermore, if we want to check if the data member, which is convertible to long
, exists, following can be used:
此外,如果我们想检查可转换为 的数据成员是否long
存在,可以使用以下方法:
template<typename T>
concept HasField = requires(T t) {
{ t.field } -> std::convertible_to<long>;
};
template <HasField T>
void fun(T const& value) {
// use value.field
}
By using C++20, we get much shorter and much more readable code that clearly expresses it's functionality.
通过使用 C++20,我们得到了更短、更易读的代码,清楚地表达了它的功能。
回答by deceleratedcaviar
This isn't an answer to your exact case, but it is an alternative answer to the question title and problem in general.
这不是对您的具体情况的答案,而是对问题标题和一般问题的替代答案。
#include <iostream>
#include <vector>
struct Foo {
size_t length() { return 5; }
};
struct Bar {
void length();
};
template <typename R, bool result = std::is_same<decltype(((R*)nullptr)->length()), size_t>::value>
constexpr bool hasLengthHelper(int) {
return result;
}
template <typename R>
constexpr bool hasLengthHelper(...) { return false; }
template <typename R>
constexpr bool hasLength() {
return hasLengthHelper<R>(0);
}
// function is only valid if `.length()` is present, with return type `size_t`
template <typename R>
typename std::enable_if<hasLength<R>(), size_t>::type lengthOf (R r) {
return r.length();
}
int main() {
std::cout <<
hasLength<Foo>() << "; " <<
hasLength<std::vector<int>>() << "; " <<
hasLength<Bar>() << ";" <<
lengthOf(Foo()) <<
std::endl;
// 1; 0; 0; 5
return 0;
}
Relevant https://ideone.com/utZqjk.
Credits to dyreshark on the freenode IRC #c++.
在 freenode IRC #c++ 上感谢 dyreshark。
回答by misterx527
I know that it's little late, however...
我知道现在有点晚了,但是......
typedef int Matrix;
struct NormalVertex {
int pos;
int normal;
};
struct Vertex {
int pos;
};
template <typename T> struct Model
{
typedef int No;
typedef char Yes;
template<typename U> static decltype (declval<U>().normal, Yes()) has_normal(U a);
static No has_normal(...);
vector<T> vertices ;
template <typename U = T>
typename enable_if<sizeof(has_normal(declval<U>())) == sizeof(Yes), void>::type
transform( Matrix m )
{
std::cout << "has .normal" << std::endl;
for (auto vertex : vertices)
{
vertex.pos = m * vertex.pos ;
vertex.normal = m * vertex.normal ;
}
}
template <typename U = T>
typename enable_if<sizeof(has_normal(declval<U>())) == sizeof(No), void>::type
transform( Matrix m )
{
std::cout << "has no .normal" << std::endl;
for (auto vertex : vertices)
{
vertex.pos = m * vertex.pos ;
}
}
} ;
int main()
{
Matrix matrix;
Model <NormalVertex> normal_model;
Vertex simple_vertex;
Model <Vertex> simple_model;
simple_model.transform(matrix);
normal_model.transform(matrix);
return 0;
}
回答by vrqq
template<
typename HTYPE,
typename = std::enable_if_t<std::is_same<decltype(HTYPE::var1), decltype(HTYPE::var1)>::value>
>
static void close_release
(HTYPE* ptr) {
ptr->var1;
}
Using enable_if and decltype to let compiler to check variable, hope to help.
使用 enable_if 和 decltype 让编译器检查变量,希望有所帮助。