Skip to content

Instantly share code, notes, and snippets.

@district10
Last active September 9, 2020 06:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save district10/aa36e68b2e95ccd90f6d7de3334f886e to your computer and use it in GitHub Desktop.
Save district10/aa36e68b2e95ccd90f6d7de3334f886e to your computer and use it in GitHub Desktop.
sfinae-example-test-is-member-function-is-static-function-is-vector-is-map-etc.cpp
#error "you should download from https://raw.githubusercontent.com/sharkdp/dbg-macro/master/dbg.h"
// https://wandbox.org/permlink/OfcEGD7GuzDbuZcp
// compile with:
// $ g++ prog.cc -std=gnu++2a -w
#include <vector>
#include <map>
#include <string>
#include <iostream>
#define HAS_GTEST 0
#if HAS_GTEST
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#define MAIN_BEGIN
#define MAIN_END
#else
#define DBG_MACRO_NO_WARNING
#include "dbg.h"
#define ASSERT_EQ(a, b) do {dbg("------------------------------");dbg(a);dbg(b);dbg((a) == (b));} while(0)
#define TEST(a, b) if (true)
#define MAIN_BEGIN int main(void) {
#define MAIN_END return 0;}
#endif
namespace detail
{
template <typename T> struct is_vector_like_impl : std::false_type
{
};
template <typename T, typename A>
struct is_vector_like_impl<std::vector<T, A>> : std::true_type
{
};
template <typename...> struct voider
{
using type = void;
};
template <typename... T> using void_t = typename voider<T...>::type;
template <typename T, typename U = void>
struct is_map_like_impl : std::false_type
{
};
template <typename T>
struct is_map_like_impl<T,
void_t<typename T::key_type, typename T::mapped_type>>
: std::true_type
{
};
} // namespace detail
template <typename T>
struct is_vector_like : detail::is_vector_like_impl<T>::type
{
};
template <typename T> struct is_map_like : detail::is_map_like_impl<T>::type
{
};
template <typename T, std::enable_if_t<is_vector_like<T>{}, int> = 0>
bool vector_or_not(const T &items)
{
return true;
}
template <typename T, std::enable_if_t<!is_vector_like<T>{}, int> = 0>
bool vector_or_not(const T &items)
{
return false;
}
template <typename T, std::enable_if_t<is_map_like<T>{}, int> = 0>
bool map_or_not(const T &items)
{
return true;
}
template <typename T, std::enable_if_t<!is_map_like<T>{}, int> = 0>
bool map_or_not(const T &items)
{
return false;
}
struct X
{
X(int v = 0) : v(v) {}
int answer() const { return 42; }
static X build(int v) { return X(v); }
int v;
};
struct Y
{
Y(int v = 0) : v(v) {}
Y build(int v) const { return Y(v); }
int v;
};
template <typename T> struct HasAnswer
{
template <typename U, int (U::*)() const> struct SFINAE
{
};
template <typename U> static char Test(SFINAE<U, &U::answer> *);
template <typename U> static int Test(...);
static const bool Has = sizeof(Test<T>(0)) == sizeof(char);
};
template <typename T, std::enable_if_t<HasAnswer<T>::Has, int> = 0>
bool has_answer(const T &t)
{
return true;
}
template <typename T, std::enable_if_t<!HasAnswer<T>::Has, int> = 0>
bool has_answer(const T &t)
{
return false;
}
template <typename T> struct HasFactory
{
template <typename U, std::enable_if_t<
//
std::is_same<U, decltype(U::build(0))>::value
//
,
int> = 0>
static char Test(int);
template <typename U> static int Test(...);
static const bool Has = sizeof(Test<T>(0)) == sizeof(char);
};
template <typename T, std::enable_if_t<HasFactory<T>::Has, int> = 0>
bool has_factory(const T &t)
{
return true;
}
template <typename T, std::enable_if_t<!HasFactory<T>::Has, int> = 0>
bool has_factory(const T &t)
{
return false;
}
MAIN_BEGIN
TEST(SfinaeTest, DistinguishVectorMap)
{
std::vector<int> nums{4, 2};
std::vector<std::string> strs{"forty", "two"};
ASSERT_EQ(vector_or_not("the answer is"), false);
ASSERT_EQ(vector_or_not(42), false);
ASSERT_EQ(vector_or_not(nums), true);
ASSERT_EQ(vector_or_not(strs), true);
std::map<int, double> kvs{{4, 2.0}};
std::map<int, std::string> kvs2{{4, "2.0"}};
ASSERT_EQ(map_or_not("the answer is"), false);
ASSERT_EQ(map_or_not(42), false);
ASSERT_EQ(map_or_not(nums), false);
ASSERT_EQ(map_or_not(strs), false);
ASSERT_EQ(map_or_not(kvs), true);
ASSERT_EQ(map_or_not(kvs2), true);
}
TEST(SfinaeTest, DoYouHaveAnswer)
{
X x;
Y y;
ASSERT_EQ(has_answer(x), true);
ASSERT_EQ(has_answer(y), false);
}
TEST(SfinaeTest, DoYouHaveFactory)
{
auto x2 = X::build(4);
ASSERT_EQ(x2.v, 4);
decltype(X::build(0)) x3(2);
ASSERT_EQ(x3.v, 2);
X x;
Y y;
ASSERT_EQ(has_factory(x), true);
ASSERT_EQ(has_factory(y), false);
}
MAIN_END