From https://stackoverflow.com/a/257382/6949852 I learned how to check whether a member function exists, then I re-write it to standardize the codes:
Now the codes become:
#include <type_traits>
#include <iostream>
struct A //has hello
{
void hello() {}
};
struct B {}; //no hello
template<typename T>
struct has_hello
{
private:
using yes = char;
using no = long;
template<typename C>
static yes has(decltype(&C::hello));
template<typename C>
static no has(...);
public:
enum name : bool {value = std::is_same<decltype(has<T>(nullptr)), yes>::value};
};
int main()
{
std::cout << static_cast<std::underlying_type<has_hello<A>::name>::type>(has_hello<A>::value) << std::endl;
std::cout << static_cast<std::underlying_type<has_hello<B>::name>::type>(has_hello<B>::value) << std::endl;
}
Compared to original codes:
- 0 ->
nullptr
- enum -> enum name : type
- sizeof -> is_same
- typeof -> decltype
-
\$\begingroup\$ It would be great to keep updates invisible, e.g. just don't mention anything happened. CR focuses on reviewing particular version of the code, and it becomes harder if the target is moving. You can add more tests/docs/explanation if you'd like though. \$\endgroup\$Incomputable– Incomputable2018年05月20日 08:49:49 +00:00Commented May 20, 2018 at 8:49
-
\$\begingroup\$ @Incomputable Ok, thx \$\endgroup\$Li Chen– Li Chen2018年05月20日 08:53:05 +00:00Commented May 20, 2018 at 8:53
-
1\$\begingroup\$ I recommend you to hold on with accepting an answer, as it discourages other people from posting their answers. Usually 1-2 days if wait time is enough. \$\endgroup\$Incomputable– Incomputable2018年05月20日 16:44:49 +00:00Commented May 20, 2018 at 16:44
-
\$\begingroup\$ @Incomputable Yes, what you said is reasonable, thx again \$\endgroup\$Li Chen– Li Chen2018年05月20日 23:42:30 +00:00Commented May 20, 2018 at 23:42
-
\$\begingroup\$ see en.cppreference.com/w/cpp/experimental/is_detected \$\endgroup\$JDługosz– JDługosz2018年05月21日 05:56:54 +00:00Commented May 21, 2018 at 5:56
1 Answer 1
Old technique
The version you're using relies on overload resolution. The current form of detection idiom relies on SFINAE. (削除) IIRC SFINAE didn't exist pre-C++11. (削除ここまで)(Thanks to @JDlugosz)
Code Review
Inherit from
std::true_type
andstd::false_type
That will spare a lot of boilerplate, and incorporates with tag dispatch quite well. It might not be directly usable in your case without some indirection and hiding into
namespace detail
.Don't use
enum
as a member wherestatic constexpr bool
will doEven though with freestanding values it is a different story due to linkage.
bool
will just bring less surprises.Provide
xxx_v
value aliases
Somewhat modern approach
Lets take somewhat more interesting example.
Identify if value of type
Element
can bepush_back
ed into container of typeContainer
.
Today, it is suggested to first "carve out" the operation itself into an alias:
template <typename Container, typename Element>
using pushback_t = decltype(std::declval<Container>().push_back(std::declval<Element>()));
Then, std::void_t
is used:
template <typename Container, typename Element, typename = std::void_t<>>
struct has_pushback : std::false_type{};
template <typename Container, typename Element>
struct has_pushback<Container, Element, std::void_t<pushback_t<Container, Element>>>:
std::true_type{};
And then _v
value alias is provided:
template <typename Container, typename Element>
inline constexpr bool has_pushback_v = has_pushback<Container, Element>::value;
Demo.
Shameless self PR: if you're a bit confused about how SFINAE works in the new version, I recommend reading this question which I've asked in the past.
Better upgrade path
When std::is_detected
will arrive, one can easily put something like this (provided a copy the operation alias from above):
template <typename Container, typename Element>
struct has_pushback : std::is_detected<pushback_t, Container, Element>
{};
That will spare even more boilerplate. See comments for already existing implementations.
-
\$\begingroup\$ Thx for your answer I'll try these approach after my ddl today \$\endgroup\$Li Chen– Li Chen2018年05月20日 23:45:45 +00:00Commented May 20, 2018 at 23:45
-
1\$\begingroup\$ ⟪IIRC SFINAE didn't exist pre-C++11.⟫ It most certainly did! I think you are thinking of expression SFINAE, in the body of a
decltype
unevaluated expression. \$\endgroup\$JDługosz– JDługosz2018年05月21日 05:55:46 +00:00Commented May 21, 2018 at 5:55 -
1
-
\$\begingroup\$ Consider adding that this tests for the existence of a single lone member with the name, instead of at least one. \$\endgroup\$Deduplicator– Deduplicator2019年05月14日 04:48:32 +00:00Commented May 14, 2019 at 4:48
Explore related questions
See similar questions with these tags.