The following (academically built, non working) code has two "problems" that I know how to solve in an ugly way. I would like a pretty one.
#include <type_traits>
template<class T> struct Integer {
Integer(T t) { static_assert(std::is_integral_v<T>, "Must be int"); }
};
template<class T> struct Floating {
Floating(T t) { static_assert(std::is_floating_point_v<T>, "Must be flating point"); }
};
template<class T> void brol(T t)
{
Integer i(t); //these two cannot work together
Floating f(t);
template<class U> auto stuff = [] (U& u) -> void //invalid syntax : no template on bloc scope
{ u *= 2; }
if(std::is_integral_v<T>)
stuff(i);
else
stuff(f);
}
int main()
{
brol(2);
brol(2.0);
}
Obviously, I cannot build an Integer and a Floating inside if the function brol(), because of the static_asserts. This problem can be easily solved with SFINAE tests, either nicely with std::enable_if_v or with some ... -> decltype( ... ) trickery. In the same way, I can also improve the end of the function body and avoid the if/else block
The lambda stuff() cannot be template (because the compiler states it cannot). I * could * make it independent and hide it in a subnamespace, but it's not so great.
HOWEVER, I cannot simply make an SFINAE test with std::enable_if, as the prototypes will only differ with their default template arguments and this is illegal (cf. documentation, section Notes in std::enable_if).
On the other hand, I don't know how to solve ussie 2 nicely...
It seems to me that std::conditional should solve all your problems
template <typename T>
void brol (T t)
{
using U = std::conditional_t<std::is_integral_v<T>, Integer<T>, Floating<T>>;
U u{t};
auto stuff = [] (U & u) -> void { u *= 2; };
stuff(u);
}
Anyway, the problem with the lambda could be solved also with a generic lambda (as pointed by rustyx)
auto stuff = [] (auto & u) -> void { u *= 2; };
Regarding the final if, in C++17 (you're using std::is_integral_v, so you're using C++17) you can also use if constexpr in similar circustances
if constexpr (std::is_integral_v<T>)
stuff(i);
else
stuff(f);
but remain the problem that you have to define i or f.
It's unclear what the purpose of your Integer and Floating is...
But regarding the "template<class U> auto stuff = [](U& u)" part, C++14 does make the lambda a template automatically if you simply use auto as the parameter type:
template<class T> void brol(T t) {
auto stuff = [](auto& u)
{ u *= 2; };
stuff(t);
}
int main() {
brol(2);
brol(2.0);
}
Related
What is the simple, idiomatic way, to check that a specific struct member validates a given concept ?
I tried the following and it does not work because { T::f } yields type float&:
#include <concepts>
struct foo {
float f;
};
// ok
static_assert(std::floating_point<decltype(foo::f)>);
template<typename T>
concept has_fp_member = requires (T t) {
{ T::f } -> std::floating_point;
};
// fails
static_assert(has_fp_member<foo>);
Where can I "remove" that useless reference being added on { T::f } ? Without making the code super ugly, adding new concepts, etc... my main requirement is that things stay readable !
e.g.
template<typename T>
concept has_fp_member = std::floating_point<decltype(T::f)>;
is very subpar, because my actual concept would check a large set of attributes, and I do not want a mess of std::foo<decltype(T::a)> && std::bar<decltype(T::b)> && ...
Note that I use float as an example but my question is about a general solution for any type / concept.
You might want to use macro:
#include <concepts>
#include <type_traits>
template <class T>
std::decay_t<T> decay_copy(T&&);
#define CHECK_MEMBER(name, type) \
{ decay_copy(t.name) } -> type
template<typename T>
concept has_member_variables = requires (T t) {
CHECK_MEMBER(f, std::floating_point);
CHECK_MEMBER(i, std::integral);
};
Demo.
Here's a partial solution but I would like to find something better (inspired from an answer to this question which has been removed)
auto prvalue(auto&& arg) { return arg; }
template<typename T>
concept has_fp_member = requires (T t) {
{ prvalue(T::f) } -> std::floating_point;
};
static_assert(has_fp_member<foo>);
It only supports cases where the member is copy-constructible though.
So I have a function that takes two possible argument types, each of which is a lambda function type I have predefined. The two possibilities are CellFType and FType. The function is nearly identical for both cases, but at one line I need it to do two different things depending on the FunctionType. I want to avoid having a whole extra overload for this so I have templated it as such
/// Returns the integral 2 norm of a function
template <typename FunctionType>
double norm(const FunctionType &f)
{
double value = 0.0;
for (size_t iT = 0; iT < n_cells; iT++)
{
QuadratureRule quadT = cell_quads[iT];
for (size_t iqn = 0; iqn < quadT.size(); iqn++)
{
double qr_weight = quadT[iqn].w;
VectorRd f_on_qr = (typeid(FunctionType) == typeid(FType<VectorRd>) ?
f(quadT[iqn].vector()) : f(quadT[iqn].vector(), cells[iT])); // *ERROR*
value += qr_weight * scalar_product(f_on_qr, f_on_qr);
}
}
return sqrt(value);
}
FType and CellFType are also both templated as such:
template <typename T>
using CellFType = std::function<T(const VectorRd &, const Cell *)>;
template <typename T>
using FType = std::function<T(const VectorRd &)>;
Why is this causing issues? How can I type test properly here?
The solution in the comments, to call an overloaded function, is of course the most straightforward to understand and therefore best approach.
But, sometimes it's nice to keep it all inlined. Since you're using C++17, there's this helper class that gets used a lot with std::visit:
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
It takes a bunch of lambdas, and converts them into a class with a call operator overload to invoke each lambda. You can use this to dispatch your case as well:
VectorRd f_on_qr = overloaded {
[&](FType<VectorRd> g) { return g(quadT[iqn].vector()); },
[&](CellFType<VectorRd> g) { return g(quadT[iqn].vector(), cells[iT])); }
} (f);
Proof of concept:
https://godbolt.org/z/G5qWGK
The idea is simple and straight-forward:
Keep breaking the n dimensional vector into n-1 dimensional constituent vectors, until you have access to the primitive-datatype objects. Then add them all.
The problem is, how to infer the return type?
It can be done like this, but it already assumes the datatype of summing variable (return-type):
typedef int SumType;
template <class T>
T Sum (const T x)
{
return x;
}
template <class T>
SumType Sum (const std::vector<T>& v)
{
SumType sum = 0;
for (const auto& x: v)
sum += Sum(x);
return sum;
}
But I don't want to do it like above. I feel like its against the spirit of meta-programming.
We must infer the return-type by keeping dissecting the vector into its constituent vectors until we reach the primitive-datatype objects, and then choose the return-type as the primitive-datatype.
Is it possible in C++ ? (I'm noob in meta-programming)
P.S.
std::accumulate() from <numeric> could have been helpful, but it by-passes the problem by inferring the return-type from its third argument __init.
This can be done without any template meta programming. You can let the compiler infer the type using auto and decltype:
template <class T>
T Sum(const T x) {
return x;
}
template <class T>
auto Sum(const std::vector<T> &v) {
decltype(Sum(v[0])) sum = 0;
for (const auto &x : v)
sum += Sum(x);
return sum;
}
The return type of Sum is automatically deduced from sum and the type of sum is whatever Sum(v[0]) returns. Eventually you will end up with the first version of Sum which returns T and the compiler knows that type.
Demo
What we can do is use T.C.'s data_type class to get the the underlying type. That is defined as
template<class T> struct voider { typedef void type; };
template<class T, class = void>
struct data_type {
typedef T type;
};
template<class T>
struct data_type<T, typename voider<typename T::value_type>::type>
: data_type<typename T::value_type> {};
Using that we can modify the primary Sum to
template <class T, class Ret = typename data_type<std::vector<T>>::type>
Ret Sum (const std::vector<T>& v)
{
Ret sum = 0;
for (const auto& x: v)
sum += Sum(x);
return sum;
}
So then you can use something like
int main()
{
std::cout << Sum(std::vector<std::vector<std::vector<int>>>{{{1},{2},{3}},{{4},{5},{6}}});
}
which outputs
21
Live Example
You've almost figured out the answer for yourself. Pay attention to this line:
sum += Sum(x);
The type of sum, which is what we’re after, must be something compatible for assignment with the result of our recursive call to Sum. One such type, given your requirements, is certainly the result type of the call.
We don't have to rely on just a fuzzy feeling though. Meta-programming is, after all, programming. You may not have realised it, but your problem is one of well-founded recursion which means that the principle of induction can guide us towards an answer.
in the base case, we have a numerical, non-vector element_type element;, meaning our result type is… element_type. you've in fact already managed this step, it’s the first overload:
template<typename T>
T Sum(T element);
in the recursive case we have:
std::vector<element_type> vec;
the induction hypothesis, i.e.:
// given
element_type element;
// we know the following is well-formed and a numerical type
using recursive_result_type = decltype( Sum(element) );
Since the vector elements have type element_type, the induction hypothesis gives us that the result of calling Sum on them has all the properties we want. (The justification for our += intuition is rooted here.) We have our anser: we use recursive_result_type as-is.
Now as it turns out that second overload cannot just be written e.g. like so:
// doesn't behave as expected
template<typename Element>
auto Sum(std::vector<Element> const& vec) -> decltype( Sum(vec.front()) );
The reason being that the current Sum overload being declared is not in scope in the return type (even though it is in the definition body). One way to work around that is to rely on class scope, which is more accommodating:
// defining a functor type with operator() overloads
// would work just as well
struct SumImpl {
template<typename Element>
static T apply(Element element)
{ return element; }
template<typename Element>
static auto apply(std::vector<Element> const& vec)
-> decltype( apply(vec.front()) )
{
using result_type = decltype( apply(vec.front()) );
result_type sum = 0;
for(auto const& element: vec) {
sum += apply(element);
}
return sum;
}
};
template<typename Arg>
using sum_result_t = decltype( SumImpl::apply(std::declval<Arg const&>()) );
template<typename Arg>
sum_result_t<Arg> Sum(Arg const& arg)
{ return SumImpl::apply(arg); }
Coliru demo
So in the past few weeks, I've been experimenting with functional-programming type solutions to problems in C++11, and from time to time, I've been in a situation where I need a function that returns a constant value.
In Haskell, there is a function
const :: a -> b -> a
const x = \_ -> x
that returns a function that evaluates to const's original argument, no matter what argument is supplied to it. I would like to create something similar in C++11. Such constructions are useful for signifying special behavior in functions (a constant function of true sent to a filter would leave the data intact). Here's my first attempt:
template<class T>
std::function<T(...)> constF(T x) {
return ([x](...) { return x; });
}
This compiles on its own, but any attempt to use it results in incomplete-type errors. My second attempt was this:
template<class T, class... Args>
std::function<T(Args...)> constF(T x) {
return ([x](Args...) { return x; });
}
This comes closer, but doesn't allow me to supply any arguments, unless I explicitly state them.
auto trueFunc1 = constF(true);
auto trueFunc2 = constF<bool, int>(true);
cout << trueFunc1() << endl; //works
cout << trueFunc1(12) << endl; //doesn't compile
cout << trueFunc2(12) << endl; //works
Ideally, a correct construction would produce no difference between trueFunc1 and trueFunc2.
Is this even possible in C++?
Since C++11 doesn't have generic or variadic lambdas, I'd write a functor template class:
template <typename T>
// requires CopyConstructible<T>
class const_function {
T value;
public:
template <typename U, typename = typename std::enable_if<std::is_convertible<U,T>::value>::type>
const_function(U&& val) :
value(std::forward<U>(val)) {}
template <typename... Args>
T operator () (Args&&...) const {
return value;
}
};
and a nice type-deducing wrapper to make them:
template <typename T>
const_function<typename std::remove_reference<T>::type>
constF(T&& t) {
return {std::forward<T>(t)};
}
In C++1y, I think the simple equivalent is:
template <typename T>
auto constF(T&& t) {
return [t{std::forward<T>(t)}](auto&&...){return t;};
}
Is it even possible to express a sort of monad" C++ ?
I started to write something like this, but stuck:
#include <iostream>
template <typename a, typename b> struct M;
template <typename a, typename b> struct M {
virtual M<b>& operator>>( M<b>& (*fn)(M<a> &m, const a &x) ) = 0;
};
template <typename a, typename b>
struct MSome : public M<a> {
virtual M<b>& operator>>( M<a>& (*fn)(M<a> &m, const a &x) ) {
return fn(*this, x);
}
private:
a x;
};
M<int, int>& wtf(M<int> &m, const int &v) {
std::cout << v << std::endl;
return m;
}
int main() {
// MSome<int> v;
// v >> wtf >> wtf;
return 0;
}
but faced the lack of polymorphism. Actually it may be my uncurrent C++ 'cause I used it last time 8 years ago. May be it possible to express general monadic interface using some new C++ features, like type inference. It's just for fun and for explaining monads to non-haskellers and non-mathematicians.
C++' type system is not powerful enough to abstract over higher-kinded types, but since templates are duck-typed you may ignore this and just implement various Monads seperately and then express the monadic operations as SFINAE templates. Ugly, but the best it gets.
This comment is bang on the money. Time and time again I see people trying to make template specializations 'covariant' and/or abuse inheritance. For better or for worse, concept-oriented generic programming is in my opinion* saner. Here's a quick demo that will use C++11 features for brevity and clarity, although it should be possible to implement the same functionality in C++03:
(*: for a competing opinion, refer to "Ugly, but the best it gets" in my quote!)
#include <utility>
#include <type_traits>
// SFINAE utility
template<typename...> struct void_ { using type = void; };
template<typename... T> using Void = typename void_<T...>::type;
/*
* In an ideal world std::result_of would just work instead of all that.
* Consider this as a write-once (until std::result_of is fixed), use-many
* situation.
*/
template<typename Sig, typename Sfinae = void> struct result_of {};
template<typename F, typename... Args>
struct result_of<
F(Args...)
, Void<decltype(std::declval<F>()(std::declval<Args>()...))>
> {
using type = decltype(std::declval<F>()(std::declval<Args>()...));
};
template<typename Sig> using ResultOf = typename result_of<Sig>::type;
/*
* Note how both template parameters have kind *, MonadicValue would be
* m a, not m. We don't whether MonadicValue is a specialization of some M<T>
* or not (or derived from a specialization of some M<T>). Note that it is
* possible to retrieve the a in m a via typename MonadicValue::value_type
* if MonadicValue is indeed a model of the proper concept.
*
* Defer actual implementation to the operator() of MonadicValue,
* which will do the monad-specific operation
*/
template<
typename MonadicValue
, typename F
/* It is possible to put a self-documenting assertion here
that will *not* SFINAE out but truly result in a hard error
unless some conditions are not satisfied -- I leave this out
for brevity
, Requires<
MonadicValueConcept<MonadicValue>
// The two following constraints ensure that
// F has signature a -> m b
, Callable<F, ValueType<MonadicValue>>
, MonadicValueConcept<ResultOf<F(ValueType<MonadicValue>)>>
>...
*/
>
ResultOf<MonadicValue(F)>
bind(MonadicValue&& value, F&& f)
{ return std::forward<MonadicValue>(value)(std::forward<F>(f)); }
// Picking Maybe as an example monad because it's easy
template<typename T>
struct just_type {
using value_type = T;
// Encapsulation omitted for brevity
value_type value;
template<typename F>
// The use of ResultOf means that we have a soft contraint
// here, but the commented Requires clause in bind happens
// before we would end up here
ResultOf<F(value_type)>
operator()(F&& f)
{ return std::forward<F>(f)(value); }
};
template<typename T>
just_type<T> just(T&& t)
{ return { std::forward<T>(t) }; }
template<typename T>
just_type<typename std::decay<T>::type> make_just(T&& t)
{ return { std::forward<T>(t) }; }
struct nothing_type {
// Note that because nothing_type and just_type<T>
// are part of the same concept we *must* put in
// a value_type member type -- whether you need
// a value member or not however is a design
// consideration with trade-offs
struct universal { template<typename T> operator T(); };
using value_type = universal;
template<typename F>
nothing_type operator()(F const&) const
{ return {}; }
};
constexpr nothing_type nothing;
It is then possible to write something like bind(bind(make_just(6), [](int i) { return i - 2; }), [](int i) { return just("Hello, World!"[i]); }). Be aware that the code in this post is incomplete in that the wrapped values aren't forwarded properly, there should be errors as soon as const-qualified and move-only types are involved. You can see the code in action (with GCC 4.7) here, although that might be a misnomer as all it does is not trigger assertions. (Same code on ideone for future readers.)
The core of the solution is that none of just_type<T>, nothing_type or MonadicValue (inside bind) are monads, but are types for some monadic values of an overarching monad -- just_type<int> and nothing_type together are a monad (sort of -- I'm putting aside the matter of kind right now, but keep in mind that it's possible to e.g. rebind template specializations after the fact, like for std::allocator<T>!). As such bind has to be somewhat lenient in what it accepts, but notice how that doesn't mean it must accept everything.
It is of course perfectly possible to have a class template M such that M<T> is a model of MonadicValue and bind(m, f) only ever has type M<U> where m has type M<T>. This would in a sense make M the monad (with kind * -> *), and the code would still work. (And speaking of Maybe, perhaps adapting boost::optional<T> to have a monadic interface would be a good exercise.)
The astute reader would have noticed that I don't have an equivalent of return here, everything is done with the just and make_just factories which are the counterparts to the Just constructor. This is to keep the answer short -- a possible solution would be to write a pure that does the job of return, and that returns a value that is implicitly convertible to any type that models MonadicValue (by deferring for instance to some MonadicValue::pure).
There are design considerations though in that the limited type deduction of C++ means that bind(pure(4), [](int) { return pure(5); }) would not work out of the box. It is not, however, an insurmountable problem. (Some outlines of a solution are to overload bind, but that's inconvenient if we add to the interface of our MonadicValue concept since any new operation must also be able to deal with pure values explicitly; or to make a pure value a model of MonadicValue as well.)
I would do it like this:
template<class T>
class IO {
public:
virtual T get() const=0;
};
template<class T, class K>
class C : public IO<K> {
public:
C(IO<T> &io1, IO<K> &io2) : io1(io1), io2(io2) { }
K get() const {
io1.get();
return io2.get();
}
private:
IO<T> &io1;
IO<K> &io2;
};
int main() {
IO<float> *io = new YYYY;
IO<int> *io2 = new XXX;
C<float,int> c(*io, *io2);
return c.get();
}