Follwing code can't compile,I just want testing SFINAE,why it can't compile?
#include <type_traits>
template<typename T>
class TestVoid {
template<std::enable_if_t<std::is_void_v<T>> * = nullptr>
void func() {
std::cout << "void\n";
}
template<std::enable_if_t<!std::is_void_v<T>> * = nullptr>
void func() {
std::cout << "none void\n";
}
};
int main() {
TestVoid<void> t;
return 0;
}
The problem is the conditions of std::enable_if don't depend on template parameter of func themselves.
You might change the code to
template<typename T>
struct TestVoid {
template<typename X = T, std::enable_if_t<std::is_void_v<X>> * = nullptr>
void func() {
std::cout << "void\n";
}
template<typename X = T, std::enable_if_t<!std::is_void_v<X>> * = nullptr>
void func() {
std::cout << "none void\n";
}
};
LIVE
When you instantiate the class template, all of the member function declarations must be valid. In your case, one of them won't be. Instead, you can delegate func to another function template.
live link
template<typename T, std::enable_if_t<std::is_void_v<T>> * = nullptr>
void func() {
std::cout << "void\n";
}
template<typename T, std::enable_if_t<!std::is_void_v<T>> * = nullptr>
void func() {
std::cout << "none void\n";
}
template<typename T>
class TestVoid {
public:
void func_member() {
func<T>();
}
};
Or, if you want to keep the actual implementation of func as a member function:
live link
template<typename T>
class TestVoid {
public:
void func_member() {
func<T>();
}
private:
template<typename U, std::enable_if_t<std::is_void_v<U>> * = nullptr>
void func() {
std::cout << "void\n";
}
template<typename U, std::enable_if_t<!std::is_void_v<U>> * = nullptr>
void func() {
std::cout << "none void\n";
}
};
Related
I had searched over 10 answers and nothing fits my current situation.
(member detector marcos comes from: http://en.wikibooks.org/wiki/More_C++_Idioms/Member_Detector)
CREATE_MEMBER_DETECTOR(normal);
CREATE_MEMBER_DETECTOR(abnormal);
template <typename T>
struct Weapon
{
//template <std::enable_if_t<Detect_normal<T>::value, T>* = nullptr>
template <std::enable_if_t<Detect_abnormal<T>::value, bool> = true>
void DefaultShoot()
{
std::cout << "special\n";
}
template <std::enable_if_t<Detect_normal<T>::value, bool> = true>
void DefaultShoot()
{
std::cout << "general\n";
}
};
struct FOO : public Weapon<FOO>
{
static constexpr auto normal = 10;
virtual void Shoot() { DefaultShoot(); }
};
Expect: The template generates a set of functions according to what constexpr I have in my subclasses.
Reality: Generate a bunch of errors and never successfully compiled...
Did anyone have a clue whether doing this in C++17 is possible?
Edit: Does the "else" possible in my situation?
This is actually my original intention.
template <typename T>
struct Weapon
{
template <std::enable_if_t<Detect_abnormal<T>::value, bool> = true>
void DefaultShoot()
{
std::cout << "special\n";
}
//template <std::enable_if_t<Detect_normal<T>::value, bool> = true>
#some magical "else" code if the one above is invalidated.
void DefaultShoot()
{
std::cout << "general\n";
}
};
You would need the template parameter from the method for SFINAE:
template <typename T>
struct Weapon
{
template <typename U = T, std::enable_if_t<Detect_abnormal<U>::value, bool> = true>
void DefaultShoot()
{
std::cout << "special\n";
}
template <typename U = T, std::enable_if_t<Detect_normal<U>::value, bool> = true>
void DefaultShoot()
{
std::cout << "general\n";
}
};
Notice that you will have ambiguous call if both are true at the same time.
As you are in C++17, you might use if constexpr:
template <typename T>
struct Weapon
{
void DefaultShoot()
{
if constexpr (Detect_abnormal<T>::value) {
std::cout << "special\n";
} else if constexpr (Detect_normal<T>::value) {
std::cout << "general\n";
} // else {}
}
};
C++20 would allow to use class template parameter in its requires:
template <typename T>
struct Weapon
{
void DefaultShoot() requires(Detect_abnormal<T>::value)
{
std::cout << "special\n";
}
void DefaultShoot() requires(Detect_normal<T>::value)
{
std::cout << "general\n";
}
};
Notice that you will have ambiguous call if both are true at the same time.
Just for information, you can use simpler detector with C++17:
#define CREATE_MEMBER_DETECTOR(X) \
template <typename T, typename = void> \
struct Detect_ ## X : std::false_type {}; \
\
template <typename T>\
struct Detect_ ## X<T, std::void_t<decltype(T::X)> > \
: std::true_type {};
I'd like to modernise a common technique I use or perhaps over use. It statically checks for method signatures and calls the methods if they exist. My approach predates C++17 by some time FWIW.
Currently, I used Boost's Type traits like BOOST_TTI_HAS_MEMBER_FUNCTION(event)
which allows something such as
template <typename M, typename E>
static inline typename std::enable_if<
has_member_function_event<current_t, void, boost::mpl::vector<M &, const E &>>::value
>::type
event(M &mux, S &g, const E &e) {
auto &node = boost::fusion::at<N>(g);
node.event(mux, e);
...
It works just fine but, you know, it's not the prettiest. Is there a way I might avoid the macros and join the rest of you in the modern world :-)?
Regards,
--Matt. (aka dinosaur)
Would simple, direct SFINAE suit your needs?
Here's a test function exercising various member functions, checking for adequate return types and const-correctness as well:
template <typename Obj> void exercise(Obj&& obj) {
if constexpr(has_bar(obj)) {
std::cout << "called T bar() -> something or void\n";
obj.bar();
}
if constexpr(converts<int>(has_foo(obj))) {
std::cout << "called int foo() const -> " << obj.foo() << "\n";
}
if constexpr(converts<long>(has_foo(obj, "some text"))) {
std::cout << "called long foo(std::string) -> " << obj.foo("some text") << "\n";
}
}
The has_bar implementation is simply:
template <typename T>
static constexpr auto has_bar(T&& obj) -> exists<decltype(obj.bar())> { return {}; }
template <typename... T>
static constexpr auto has_bar(T&&...) -> does_not_exist { return {}; }
To generically allow for checking signatures and avoid repetitious code, here's a helper macro (obviously optional):
#define DEF_HAS_MEMBER(name) \
template <typename T, typename... Args> \
static constexpr auto has_##name(T&& obj, Args&&... args) \
-> exists<decltype(std::forward<T>(obj).name(std::forward<Args>(args)...))> { return {}; } \
template <typename... T> \
static constexpr auto has_##name(T&&...) -> does_not_exist { return {}; }
DEF_HAS_MEMBER(foo)
DEF_HAS_MEMBER(bar)
The converts predicate now is an ultra-simple addition:
template <typename T, typename R>
static constexpr auto converts(R) { return std::is_convertible_v<typename R::return_type, T>; }
Everything together:
Live On Coliru
#include <string>
#include <type_traits>
#include <iostream>
template <typename R> struct exists : std::true_type { using return_type = R; };
struct does_not_exist : std::false_type { using return_type = void; };
#define DEF_HAS_MEMBER(name) \
template <typename T, typename... Args> \
static constexpr auto has_##name(T&& obj, Args&&... args) \
-> exists<decltype(std::forward<T>(obj).name(std::forward<Args>(args)...))> { return {}; } \
template <typename... T> \
static constexpr auto has_##name(T&&...) -> does_not_exist { return {}; }
DEF_HAS_MEMBER(foo)
DEF_HAS_MEMBER(bar)
struct Everything {
int foo(std::string /*unused*/) { return 42; }
int foo() const { return -1; }
void bar() {}
};
struct Some {
int foo() const { return -2; }
};
template <typename T, typename R>
static constexpr auto converts(R) { return std::is_convertible_v<typename R::return_type, T>; }
template <typename Obj> void exercise(Obj&& obj) {
std::cout << "===== " << __PRETTY_FUNCTION__ << "\n";
if constexpr(has_bar(obj)) {
std::cout << "called T bar() -> something or void\n";
obj.bar();
}
if constexpr(converts<int>(has_foo(obj))) {
std::cout << "called int foo() const -> " << obj.foo() << "\n";
}
if constexpr(converts<long>(has_foo(obj, "some text"))) {
std::cout << "called long foo(std::string) -> " << obj.foo("some text") << "\n";
}
}
int main() {
Everything e;
Everything const ce;
Some s;
Some const cs;
exercise(s);
exercise(cs);
exercise(ce);
exercise(e);
}
Prints
===== void exercise(Obj&&) [with Obj = Some&]
called int foo() const -> -2
===== void exercise(Obj&&) [with Obj = const Some&]
called int foo() const -> -2
===== void exercise(Obj&&) [with Obj = const Everything&]
called int foo() const -> -1
===== void exercise(Obj&&) [with Obj = Everything&]
called T bar() -> something or void
called int foo() const -> -1
called long foo(std::string) -> 42
OK. I have taken Alan Birtles advice and had a look at C++20 concepts for the solution.
Perhaps the use of std::addressof is overkill but it makes it almost a one-liner without a macro to define a HasMethodXYZ concept which may then be used for if constexpr or for easy SFINAE via a constraint. For example:
template <typename T>
concept HasMethodEvent = requires(T a, void (T::*m)(const std::string&) const) {
{&a == std::addressof(a)};
{m = &T::event};
};
struct dude_noway {};
struct dude_no {
void event(std::string& f) const {}
};
struct dude_yes {
void event(const std::string& f) const {}
};
template <typename T>
bool perhaps_event() {
if constexpr (HasMethodEvent<T>) {
return true;
} else {
return false;
}
}
template <HasMethodEvent T>
bool perhaps_event_sfinae() {
return true;
}
template <typename T>
bool perhaps_event_sfinae() {
return false;
}
//Catch2 test-case check
TEST_CASE("simple event check", "[check_method]") {
REQUIRE(perhaps_event<dude_yes>());
REQUIRE_FALSE(perhaps_event<dude_no>());
REQUIRE_FALSE(perhaps_event<dude_noway>());
REQUIRE(perhaps_event_sfinae<dude_yes>());
REQUIRE_FALSE(perhaps_event_sfinae<dude_no>());
REQUIRE_FALSE(perhaps_event_sfinae<dude_noway>());
}
which works OK with clang++-10 using libstdc++-10. For the win, I prefer this to the Boost TTI approach as it co-locates the method signature with the method name as part of the concept rather than using the MPL vector later and it feels simpler.
Thanks, --Matt.
I'm trying to use template specialization to return different types based on the value of the template variable.
I've moved from trying to branch at runtime rather than compile time using typeof(), unspecialized templates and using std::enable_if_t<>. I think this may stem from a lack of understanding about how the template functions are resolving.
class Test
{
public:
template <typename T>
T request()
{
T ret = getVal<T>();
return ret;
}
private:
float foo = 2.f;
int bar = 1;
template <typename T>
typename std::enable_if<std::is_same<T, float>::value, bool>::type
getVal() { return foo; }
template <typename T>
typename std::enable_if<std::is_same<T, int>::value, bool>::type
getVal() { return bar; }
template<typename T>
T getVal()
{
std::cout << "T is type " << typeid(T).name() << std::endl;
throw std::bad_typeid();
}
};
int main()
{
Test t;
int i;
float f;
i = t.template request<int>();
f = t.template request<float>();
}
I'm expecting this to resolve to three different functions, but I'm not sure if it is:
T Test::getVal()
int Test::getVal()
float Test::getVal()
Any help would be greatly appreciated.
You can do this pretty easily by specializing getVal(), though you may have oversimplified the question
class Test {
public:
template <typename T>
T request() {
T ret = getVal<T>();
return ret;
}
private:
float foo = 2.f;
int bar = 1;
template<typename T>
T getVal() {
std::cout << "T is type " << typeid(T).name() << std::endl;
throw std::bad_typeid();
}
};
// add specializations
template<>
float Test::getVal<float>() { return foo; }
template <>
int Test::getVal<int>() { return bar; }
int main() {
Test t;
int i = t.request<int>(); // don't need template keyword here
float f = t.request<float>();
}
If you're able to use c++17, it is even simpler with if constexpr and a single getVal
template<typename T>
auto getVal() {
if constexpr (std::is_same_v<int, T>) {
return foo;
} else if constexpr (std::is_same_v<float, T>) {
return bar;
} else {
std::cout << "T is type " << typeid(T).name() << std::endl;
throw std::bad_typeid();
}
}
Your problem is that template<typename T> T getVal() make call ambiguous when the SFINAEd one succeed.
One solution is to restrict that one with complement condition...
But tag dispatching is an easy alternative way to fix your issue:
template <typename> struct Tag{};
class Test
{
public:
template <typename T>
T request() const
{
return getVal(Tag<T>{});
}
private:
float foo = 2.f;
int bar = 1;
float getVal(Tag<float>) const { return foo; }
int getVal(Tag<int>) const { return bar; }
template<typename T> void getVal(Tag<T>) = delete;
};
I have a class like this to call a function depending on the type. I try to compile it, but have error error C2059 syntax error : 'template'
class A
{
call_1()
{
B<type> b;
b.template say(i);
}
template<class T>
struct B
{
template <typename T, typename I>
T say(I i) {
return word;
}
};
template<>
struct B<void>
{
template <typename T, typename I>
void say(I i) {
/**/
}
};
}
What am I doing wrong?
First, let's rewrite your example into something that is readable and is closer to being compilable, and we also print "1" or "2" in say() to know which function gets called:
#include <iostream>
using type = int;
class A {
void call_1() {
B<type> b;
int i = 0;
b.template say(i);
}
template<class T>
struct B
{
template <typename T, typename I>
T say(I i) {
std::cout << "1\n";
return T();
}
};
template<>
struct B<void>
{
template <typename T, typename I>
void say(I i) {
std::cout << "2\n";
}
};
};
OK, so first, you are trying to specialize B inside of A. This is not allowed, so let't move it outside of A:
using type = int;
class A {
void call_1() {
B<type> b;
int i = 0;
b.template say(i);
}
template<class T>
struct B
{
template <typename T, typename I>
T say(I i) {
std::cout << "1\n";
return T();
}
};
};
template<>
struct A::B<void>
{
template <typename T, typename I>
void say(I i) {
std::cout << "2\n";
}
};
Next up, you are using the same template parameter (T) in both B and say(). You don't need to repeat T, so let's delete it:
using type = int;
class A {
void call_1() {
B<type> b;
int i = 0;
b.template say(i);
}
template<class T>
struct B
{
template <typename I>
T say(I i) {
std::cout << "1\n";
return T();
}
};
};
template<>
struct A::B<void>
{
template <typename I>
void say(I i) {
std::cout << "2\n";
}
};
Finally, call_1() cannot be defined before the specialization of A::B, so we need to move it outside too:
using type = int;
class A {
void call_1();
template<class T>
struct B
{
template <typename I>
T say(I i) {
std::cout << "1\n";
return T();
}
};
};
template<>
struct A::B<void>
{
template <typename I>
void say(I i) {
std::cout << "2\n";
}
};
void A::call_1() {
B<type> b;
int i = 0;
b.template say(i);
}
This should now compile and do what you want. Calling call_1() will print 1. If you change the type from int to void:
using type = void;
it will print 2.
Partial specialization for member functions template arguments is possible? I'm not sure, but it is worth a try.
This works just fine (http://coliru.stacked-crooked.com/a/795e953af7537ab6):
#include <iostream>
struct Foo { void Bar() { std::cout << "Bar()" << std::endl; } };
struct Foo2 { void Bar2() { std::cout << "Bar2()" << std::endl; } };
template <typename TClass, void(TClass::*t_func)()>
void function()
{
TClass p;
(p.*t_func)();
}
template <typename TClass, void(TClass::*t_func)(), typename TClass2, void(TClass2::*t_func2)(), typename ...Rest>
void function()
{
function<TClass, t_func>();
function<TClass2, t_func2, Rest...>();
}
int main()
{
function<Foo, &Foo::Bar, Foo2, &Foo2::Bar2>();
}
Output:
Bar()
Bar2()
The next sample also works (http://coliru.stacked-crooked.com/a/e8fe14dde6932f4c):
#include <iostream>
struct Foo { Foo() { std::cout << "Foo()" << std::endl; } };
struct Foo2 { Foo2() { std::cout << "Foo2()" << std::endl; } };
template <typename... Args>
struct Impl;
template <typename TClass, typename ...Rest>
struct Impl<TClass, Rest...>
{
static void function()
{
TClass p;
Impl<Rest...>::function();
}
};
template <>
struct Impl<>
{
static void function(){ std::cout << "EmptyImpl" << std::endl; }
};
template <typename ...Args>
struct Factory
{
Factory()
{
Impl<Args...>::function();
}
};
int main()
{
auto f = Factory<Foo, Foo2>();
}
Output:
Foo()
Foo2()
EmptyImpl
But if I want to combine these two things above:
#include <iostream>
struct Foo { void Bar() { std::cout << "Bar()" << std::endl; } };
struct Foo2 { void Bar2() { std::cout << "Bar2()" << std::endl; } };
template <typename... Args>
struct Impl;
template <typename TClass, void(TClass::*t_func)(), typename ...Rest>
struct Impl<TClass, decltype(t_func), Rest...>
{
static void function()
{
TClass p;
Impl<Rest...>::function();
}
};
template <>
struct Impl<>
{
static void function(){}
};
template <typename ...Args>
struct Factory
{
Factory()
{
Impl<Args...>::function();
}
};
int main()
{
auto f = Factory<Foo, &Foo::Bar, Foo2, &Foo2::Bar2>();
}
it will be a compiler error:
main.cpp: In function 'int main()':
main.cpp:36:59: error: type/value mismatch at argument 1 in template parameter list for 'template<class ... Args> struct Factory'
auto f = Factory<Foo, &Foo::Bar, Foo2, &Foo2::Bar2>();
main.cpp:36:59: note: expected a type, got '&Foo::Bar'
main.cpp:36:59: error: type/value mismatch at argument 1 in template parameter list for 'template<class ... Args> struct Factory'
main.cpp:36:59: note: expected a type, got '&Foo2::Bar2'
Any idea? What did I miss? :)
consider using additional wrapper for calling member functions
#include <iostream>
struct Foo { void Bar() { std::cout << "Bar()" << std::endl; } };
struct Foo2 { void Bar2() { std::cout << "Bar2()" << std::endl; } };
template <class TClass>
using FType = void(TClass::*)();
template<class TClass, FType<TClass> t_func>
class Caller
{
public:
Caller()
{
TClass p;
(p.*t_func)();
}
};
template <typename... Args>
struct Impl;
template <class TClass, typename ...Rest>
struct Impl<TClass, Rest...>
{
static void function()
{
TClass p;
Impl<Rest...>::function();
}
};
template <>
struct Impl<>
{
static void function(){}
};
template <class ...Args>
struct Factory
{
Factory()
{
Impl<Args...>::function();
}
};
int main()
{
auto f = Factory<Caller<Foo, &Foo::Bar>, Caller<Foo2, &Foo2::Bar2> >();
}