Deduct template parameter fail while using if constexpr - c++

I am trying to figure out how the sfinae concept works in C++. But I can't convince the object-type compiler if bool is true or false.
#include <iostream>
class A {
public:
void foo() { std::cout << "a\n"; }
};
class B {
public:
void ioo() { std::cout << "b\n"; }
};
template<class T>
void f(const T& ob, bool value = false)
{
if constexpr (!value) ob.foo();
else ob.ioo();
}
int main()
{
A ob1;
B ob2;
f(ob1, true);
f(ob2, false);
}

You need to let the bool parameter to be part of template. In your case, bool value is a run time parameter.
By adding the value as non-template parameter, your code can compile:
template<bool Flag, class T>
// ^^^^^^^^
void f(const T& ob)
{
if constexpr (Flag) {
ob.foo();
}
else
ob.ioo();
}
and you may call like:
f<true>(ob1);
f<false>(ob2);
As a side note, your A::foo() and B::ioo() must be const qualified member functions, as you want to call, with a const objects of each classes inside the f.
That being said, the bool parameter is redundant if you can use the std::is_same
#include <type_traits> // std::is_same
template<class T>
void f(const T& ob)
{
if constexpr (std::is_same_v<T, A>) {
ob.foo();
}
else if constexpr (std::is_same_v<T, B>)
ob.ioo();
}
Now call needs to be just:
f(ob1);
f(ob2);

Related

How to check a type has constexpr constructor

I want my class use another implementation for types don't have constexpr constructor.
like this:
template <typename A>
class foo
{
public:
// if A has constexpr constructor
constexpr foo() :_flag(true) { _data._a = A(); }
// else
constexpr foo() : _flag(false) { _data.x = 0; }
~foo(){}
bool _flag;
union _data_t
{
_data_t() {} // nothing, because it's just an example
~_data_t() {}
A _a;
int x;
}_data;
};
To achieve what the title says, I try this:
template<typename _t, _t = _t()>
constexpr bool f()
{
return true;
}
template<typename _t>
constexpr bool f()
{
return false;
}
It works well for types haven't constexpr constructor.
But for other types it causes a compile error with ambiguous overloads.
so how can I check?
I suppose you can use SFINAE together with the power of the comma operator
Following your idea, you can rewrite your f() functions as follows
template <typename T, int = (T{}, 0)>
constexpr bool f (int)
{ return true; }
template <typename>
constexpr bool f (long)
{ return false; }
Observe the trick: int = (T{}, 0) for the second template argument
This way f() is enabled (power of the comma operator) only if T{} can be constexpr constructed (because (T{}, 0) is the argument for a template parameter), otherwise SFINAE wipe away the first version of f().
And observe that the fist version of f() receive an unused int where the second one receive a long. This way the first version is preferred, when available, calling f() with an int; the second one is selected, as better than nothing solution, when the first one is unavailable (when the first template argument isn't constexpr default constructible).
Now you can construct two template constructors for foo that you can alternatively enable/disable according the fact the template parameter T (defaulted to A) is or isn't constexpr constructible
template <typename T = A,
std::enable_if_t<f<T>(0), std::nullptr_t> = nullptr>
constexpr foo() { std::cout << "constexpr" << std::endl; }
template <typename T = A,
std::enable_if_t<not f<T>(0), std::nullptr_t> = nullptr>
constexpr foo() { std::cout << "not constexpr" << std::endl; }
The following is a full compiling example (C++14 or newer, but you can modify it for C++11):
#include <iostream>
#include <type_traits>
template <typename T, int = (T{}, 0)>
constexpr bool f (int)
{ return true; }
template <typename>
constexpr bool f (long)
{ return false; }
template <typename A>
struct foo
{
template <typename T = A,
std::enable_if_t<f<T>(0), std::nullptr_t> = nullptr>
constexpr foo() { std::cout << "constexpr" << std::endl; }
template <typename T = A,
std::enable_if_t<not f<T>(0), std::nullptr_t> = nullptr>
constexpr foo() { std::cout << "not constexpr" << std::endl; }
};
struct X1 { constexpr X1 () {} };
struct X2 { X2 () {} };
int main()
{
foo<X1> f1; // print "constexpr"
foo<X2> f2; // print "not constexpr"
}

Check for function existance on other type using C++ concepts

Does anybody know how to make a C++ concept T such that the function g is only defined for arguments t with type T if there exist an overload of f in B that accepts an argument t?
struct A1 {};
struct A2 {};
struct B {
void f(A1 a1) {}
};
void g(T t) {
B b;
b.f(t);
}
As an example, I want to define a to_string for everything that std::stringstream accepts, and define something like
std::string to_string(T t) {
std::stringstream ret;
ret << t;
return ret.str();
}
All examples on concepts deal with the easier case of requiring the existance of a function on a type, while in this case we want to check existance of a function on another type.
If you want to check if the type is streamable or not, you can have something like:
#include <iostream>
#include <concepts>
#include <sstream>
template <typename T>
concept Streamable = requires (T x, std::ostream &os) { os << x; };
struct Foo {};
struct Bar {};
std::ostream& operator<<(std::ostream& os, Foo const& obj) {
// write obj to stream
return os;
}
template <Streamable T>
std::string to_string(T t) {
std::stringstream ret;
ret << t;
return ret.str();
}
int main() {
Foo f;
Bar b;
to_string(f);
to_string(b); // error
return 0;
}
Demo
You can use two different type placeholders in a single concept, to require both the existence of a member function for an instance of one of the type placeholders, as well as the argument to said member function to match the type of another placeholder. E.g.:
#include <iostream>
template<typename T, typename U>
concept HasMemFnConstFoo = requires(const T t, const U u) {
t.foo(u);
};
template<typename U>
struct Bar {
template <typename T>
static void bar(const T& t)
{
if constexpr (HasMemFnConstFoo<T, U>) { t.foo(U{}); }
else { std::cout << "foo() not defined\n"; }
}
};
struct A1 {};
struct A2 {};
struct B1 {
void foo(const A1&) const { std::cout << "B1::foo()\n"; }
};
struct B2 {
void foo(const A1&) { std::cout << "B2::foo()\n"; }
};
struct B3 {
void foo(A1&) const { std::cout << "B3::foo()\n"; }
};
int main() {
Bar<A1>::bar(B1{}); // B1::foo()
Bar<A2>::bar(B1{}); // foo() not defined
Bar<A1>::bar(B2{}); // foo() not defined [note: method constness]
Bar<A2>::bar(B2{}); // foo() not defined
Bar<A1>::bar(B3{}); // foo() not defined [note: argument constness]
Bar<A2>::bar(B3{}); // foo() not defined
}

How to pass const member function as non-const member function

How to pass a const member function as a non-const member function to the template?
class TestA
{
public:
void A() {
}
void B() const {
}
};
template<typename T, typename R, typename... Args>
void regFunc(R(T::*func)(Args...))
{}
void test()
{
regFunc(&TestA::A); // OK
regFunc(&TestA::B); // ambiguous
}
Don't want to add something like:
void regFunc(R(T::*func)(Args...) const)
Is there a better way?
Why not simply pass it to a generic template function:
see live
#include <iostream>
#include <utility>
class TestA
{
public:
void A() { std::cout << "non-cost\n"; }
void B() const { std::cout << "cost with no args\n"; }
void B2(int a) const { std::cout << "cost with one arg\n"; }
const void B3(int a, float f) const { std::cout << "cost with args\n"; }
};
template<class Class, typename fType, typename... Args>
void regFunc(fType member_fun, Args&&... args)
{
Class Obj{};
(Obj.*member_fun)(std::forward<Args>(args)...);
}
void test()
{
regFunc<TestA>(&TestA::A); // OK
regFunc<TestA>(&TestA::B); // OK
regFunc<TestA>(&TestA::B2, 1); // OK
regFunc<TestA>(&TestA::B3, 1, 2.02f); // OK
}
output:
non-cost
cost with no args
cost with one arg: 1
cost with args: 1 2.02
No, you have to specify the cv and ref qualifiers to match. R(T::*func)(Args...) is a separate type to R(T::*func)(Args...) const for any given R, T, Args....
As a terminology note, it isn't ambiguous. There is exactly one candidate, it doesn't match. Ambiguity requires multiple matching candidates.

How to call a function, passing the return value (possibly void) of a functor?

Given a function that calls a templated function argument and calls another function that does something with the returned value:
template <typename T>
void doSomething(T &&) {
// ...
}
template <typename T_Func>
void call(T_Func &&func) {
doSomething(func());
}
How can this be extended to work with a functor that returns void? Ideally, I would like to add an overloaded void doSomething() { ... } that is called if func's return type is void.
Currently this just results in an error: invalid use of void expression if func returns void.
Working example on Ideone
I think you could create a struct helper to use overloaded , operator more or less like this:
#include <type_traits>
#include <utility>
struct my_void { };
struct my_type { };
template <class T, typename std::enable_if<std::is_void<T>::value>::type* = nullptr>
my_void operator,(T, my_type) { return {}; }
template <class T, typename std::enable_if<!std::is_void<T>::value>::type* = nullptr>
T &&operator,(T &&val, my_type) { return std::forward<T>(val); }
template <typename T>
void doSomething(T &&) {
}
template <typename T_Func>
void call(T_Func &&func) {
doSomething((func(), my_type{}));
}
int main() {
auto func1 = []() -> bool { return true; };
auto func2 = []() -> void { };
call(func1);
call(func2);
}
[live demo]
Edit:
Thanks to Piotr Skotnicki and Holt (they pointed out that the first overload actually wouldn't ever be triggered and proposed simplified version of the approach):
#include <type_traits>
#include <utility>
struct dumb_t { };
template <class T>
T &&operator,(T &&val, dumb_t) { return std::forward<T>(val); }
template <typename T>
void doSomething(T &&) {
}
template <typename T_Func>
void call(T_Func &&func) {
doSomething((func(), dumb_t{}));
}
int main() {
auto func1 = []() -> bool { return true; };
auto func2 = []() -> void { };
call(func1);
call(func2);
}
[live demo]
doSomething() takes a parameter, and a parameter cannot be void.
So, in order for this to work, you also need an overloaded doSomething() that takes no parameters. This is going to be the first step:
template <typename T>
void doSomething(T &&) {
// ...
}
void doSomething()
{
}
So, you're going to have to do this first, before you can even get off the ground.
It's also possible that you would like to supply a default value for the parameter, in case the functor returns a void; and still use a single template. That's another possibility, and the following solution can be easily adjusted, in an obvious way, to handle that.
What needs to happen here is a specialization of call() for a functor that returns a void. Unfortunately, functions cannot be partially specialized, so a helper class is needed:
#include <utility>
template <typename T>
void doSomething(T &&) {
// ...
}
void doSomething()
{
}
// Helper class, default implementation, functor returns a non-void value.
template<typename return_type>
class call_do_something {
public:
template<typename functor>
static void call(functor &&f)
{
doSomething(f());
}
};
// Specialization for a functor that returns a void.
//
// Trivially changed to call the template function instead, with
// a default parameter.
template<>
class call_do_something<void> {
public:
template<typename functor>
static void call(functor &&f)
{
f();
doSomething();
}
};
// The original call() function is just a wrapper, that selects
// the default or the specialized helper class.
template <typename T_Func>
void call(T_Func &&func) {
call_do_something<decltype(func())>::call(std::forward<T_Func>(func));
}
// Example:
void foobar()
{
call([] { return 1; });
call([] {});
}
You can provide an extra pair of overloaded helper functions (named callDispatch in my example below) to dispatch the call as required, which eliminates the need for partial specialisation and thus helper classes. They are overloaded by using different signature specifications for the std::function objects they take (live code here):
#include <iostream>
#include <functional>
int func1()
{
return 1;
}
void func2()
{
}
template <typename T>
void doSomething(T &&)
{
std::cout << "In param version" << std::endl;
// ...
}
void doSomething()
{
std::cout << "In no-param version" << std::endl;
// ...
}
template <typename R, typename ... Args>
void callDispatch(std::function<R(Args...)> &&f)
{
doSomething(f());
}
template <typename ... Args>
void callDispatch(std::function<void(Args...)> &&f)
{
f();
doSomething();
}
template <typename T>
void call(T &&func) {
callDispatch(std::function<std::remove_reference_t<T>>(func));
}
int main() {
call(func1);
call(func2);
}
One lean variant would be to give the method a function as parameter. Then you evaluate the expression inside the method and see if did anything. In general this is usally bad practice, since you usually can infer how it returns stuff and when it is needed.

Accessing a member in a template: how to check if the template is a pointer or not?

Given the following declaration:
template<class T>
class A {
void run(T val) {
val.member ...
}
}
This code works fine if no pointers are used:
A<Type> a;
Type t;
a.run(t);
But using a pointer results in an error:
A<Type*> a;
Type* t = new Type();
a.run(t);
error: request for member ‘member’ which is of non-class type ‘T*’
Obviously in this case the member must be accessed via ->. What's the best way to handle this?
I found a solution on SO: Determine if Type is a pointer in a template function
template<typename T>
struct is_pointer { static const bool value = false; };
template<typename T>
struct is_pointer<T*> { static const bool value = true; };
...
if (is_pointer<T>::value) val->member
else val.member
But this is very verbose. Any better ideas?
You could use a simple pair of overloaded function templates:
template<typename T>
T& access(T& t) { return t; }
template<typename T>
T& access(T* t) { return *t; }
And then use them this way:
access(val).member = 42;
For instance:
template<typename T>
struct A
{
void do_it(T& val)
{
access(val).member = 42;
}
};
struct Type
{
int member = 0;
};
#include <iostream>
int main()
{
A<Type> a;
Type t;
a.do_it(t);
std::cout << t.member << std::endl;
A<Type*> a2;
Type* t2 = new Type(); // OK, I don't like this, but just to show
// it does what you want it to do...
a2.do_it(t2);
std::cout << t2->member;
delete t2; // ...but then, don't forget to clean up!
}
Here is a live example.
The best idea is probably to specialize your class for pointer types.
template<class T>
class A{ ...};
template<>
class A<T*> { //implement for pointers
};
If you feel that this is too verbose, you can use overload a get_ref function:
template<class T> T& get_ref(T & r) {return r;}
template<class T> T& get_ref(T* r) {return *r;}
template<class T>
class A {
void do(T val) {
get_ref(val).member ...
}
}