3
\$\begingroup\$

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:

  1. 0 -> nullptr
  2. enum -> enum name : type
  3. sizeof -> is_same
  4. typeof -> decltype
asked May 20, 2018 at 8:24
\$\endgroup\$
5
  • \$\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\$ Commented May 20, 2018 at 8:49
  • \$\begingroup\$ @Incomputable Ok, thx \$\endgroup\$ Commented 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\$ Commented May 20, 2018 at 16:44
  • \$\begingroup\$ @Incomputable Yes, what you said is reasonable, thx again \$\endgroup\$ Commented May 20, 2018 at 23:42
  • \$\begingroup\$ see en.cppreference.com/w/cpp/experimental/is_detected \$\endgroup\$ Commented May 21, 2018 at 5:56

1 Answer 1

5
\$\begingroup\$

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 and std::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 where static constexpr bool will do

    Even 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 be push_backed into container of type Container.

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.

answered May 20, 2018 at 10:15
\$\endgroup\$
4
  • \$\begingroup\$ Thx for your answer I'll try these approach after my ddl today \$\endgroup\$ Commented 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\$ Commented May 21, 2018 at 5:55
  • 1
    \$\begingroup\$ "when it will arrive..." see my file to use in the mean time. \$\endgroup\$ Commented May 21, 2018 at 5:59
  • \$\begingroup\$ Consider adding that this tests for the existence of a single lone member with the name, instead of at least one. \$\endgroup\$ Commented May 14, 2019 at 4:48

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.