Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 51bc094

Browse files
WIP: Convert to use enable_if_base_of
1 parent 3913a2b commit 51bc094

File tree

1 file changed

+93
-78
lines changed

1 file changed

+93
-78
lines changed

cores/arduino/Print.h

Lines changed: 93 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,27 @@ struct enable_if_valid {
4242
};
4343
template <typename Check, typename T> using enable_if_valid_t = typename enable_if_valid<Check, T>::type;
4444

45+
46+
namespace detail {
47+
// Returns a value of the given type. No implementation, so this is
48+
// meant for use in decltype only. Identical to std::declval.
49+
template <typename T> T declval();
50+
51+
// Function that accept a pointer of the given type. Can be used to
52+
// detect if another type is convertible to T.
53+
template<typename T>
54+
void accepts_pointer_of_type(const T*);
55+
56+
// Simplified and integrated version of std::enable_if_t and
57+
// std::is_base_of (which are not available on AVR). Integrating them
58+
// makes things more specific and thus simpler.
59+
// TODO: This check does not detect private base classes. To do so, a
60+
// more complicated check is needed, something like
61+
// https://stackoverflow.com/questions/2910979/how-does-is-base-of-work
62+
template<typename Base, typename Derived>
63+
using enable_if_base_of = decltype(accepts_pointer_of_type<Base>(declval<Derived*>()));
64+
}
65+
4566
/* Forward declarations */
4667
namespace Formatters {
4768
template<typename THead, typename TTail = void>
@@ -89,34 +110,6 @@ class Print
89110
size_t println(void);
90111

91112
virtual void flush() { /* Empty implementation for backward compatibility */ }
92-
/*
93-
template<typename T, typename ...Ts>
94-
_always_inline size_t print(const T &arg, const Ts &...args) {
95-
// This might lead to infinite template instantion
96-
//return print(arg, DefaultFormatter<>(), args...);
97-
size_t n = DefaultFormatter<>().printTo(this, arg);
98-
return n + print(args...);
99-
}
100-
101-
template<typename T, typename T2, typename ...Ts>
102-
_always_inline auto print(const T &arg, const T2 &arg2, const Ts &...args)
103-
-> enable_if_valid_t<decltype(arg2.printTo(this, arg)), size_t> {
104-
size_t n = arg2.printTo(this, arg);
105-
return n + print(args...);
106-
}
107-
108-
template<typename T, typename T2, typename T3, typename ...Ts>
109-
_always_inline auto print(const T &arg, const T2 &arg2, const T3 &arg3, const Ts &...args)
110-
-> enable_if_valid_t<decltype(arg2.addOption(arg3)), size_t> {
111-
return print(arg, arg2.addOption(arg3), args...);
112-
}
113-
114-
template<typename T, typename T2, typename ...Ts>
115-
_always_inline auto print(const T &arg, const T2 &arg2, const Ts &...args)
116-
-> enable_if_valid_t<decltype(DefaultFormatter<>().addOption(arg2)), size_t> {
117-
return print(arg, DefaultFormatter<>().addOption(arg2), args...);
118-
}
119-
*/
120113

121114
template<typename ...Ts> _always_inline size_t print(const Ts &...args) { return printMultiple(args...); }
122115
template<typename ...Ts> _always_inline size_t println(const Ts &...args) { size_t t = print(args...); return t + println(); }
@@ -153,31 +146,40 @@ class Print
153146
// A value and a formatter is specified without any options (or the
154147
// below overloads have applied the options): Let the formatter
155148
// print the value.
156-
template<typename T, typename TFormatter, typename ...Ts>
157-
_always_inline auto printMultiple(const T &arg, const TFormatter &formatter, const Ts &...args)
158-
-> enable_if_valid_t<decltype(accepts_formatter(&formatter)), size_t> {
159-
//-> enable_if_valid_t<decltype(formatter.printTo(p, arg)), size_t> {
149+
template<
150+
typename T,
151+
typename TFormatter,
152+
typename ...Ts,
153+
detail::enable_if_base_of<Print::Formatter, TFormatter>* = nullptr
154+
>
155+
_always_inline size_t printMultiple(const T &arg, const TFormatter &formatter, const Ts &...args) {
160156
size_t n = formatter.printTo(this, arg);
161157
return n + printMultiple(args...);
162158
}
163159

164-
165160
// A value, a formatter and an option is specified: Apply the option
166161
// to the formatter.
167-
template<typename T, typename TFormatter, typename TOption, typename ...Ts>
168-
_always_inline auto printMultiple(const T &arg, const TFormatter &formatter, const TOption &option, const Ts &...args)
169-
//-> enable_if_valid_t<decltype(formatter + option), size_t> {
170-
-> enable_if_valid_t<decltype(accepts_formatter(&formatter), accepts_option(&option)), size_t> {
162+
template<
163+
typename T,
164+
typename TFormatter,
165+
typename TOption,
166+
typename ...Ts,
167+
detail::enable_if_base_of<Print::Formatter, TFormatter>* = nullptr,
168+
detail::enable_if_base_of<Print::FormatterOption, TOption>* = nullptr
169+
>
170+
_always_inline size_t printMultiple(const T &arg, const TFormatter &formatter, const TOption &option, const Ts &...args) {
171171
return printMultiple(arg, formatter + option, args...);
172172
}
173173

174-
175174
// A value and an option is specified: Look up the default formatter
176175
// for this value and option and add it to the argument list.
177-
template<typename T, typename TOption, typename ...Ts>
178-
_always_inline auto printMultiple(const T &arg, const TOption &option, const Ts &...args)
179-
//-> enable_if_valid_t<decltype(DefaultFormatterFor(arg, option)), size_t> {
180-
-> enable_if_valid_t<decltype(accepts_option(&option)), size_t> {
176+
template<
177+
typename T,
178+
typename TOption,
179+
typename ...Ts,
180+
detail::enable_if_base_of<Print::FormatterOption, TOption>* = nullptr
181+
>
182+
_always_inline size_t printMultiple(const T &arg, const TOption &option, const Ts &...args) {
181183
auto formatter = DefaultFormatterFor(arg, option);
182184
return printMultiple(arg, formatter, option, args...);
183185
}
@@ -187,27 +189,35 @@ class Print
187189
// operator+ to apply each of its arguments to the formatter in
188190
// turn), but without these the error messages are less clear if
189191
// incompatible options are mixed (with the below overloads the
190-
// error shows the formatter and the incompatible option, while
191-
// without them only the formatter and the entire option list are
192+
// error shows the formatter and the incompatible option, while // without them only the formatter and the entire option list are
192193
// shown.
193194
//
194195
// If we keep these, OptionList::addToFormatter and the related
195196
// operator+ overload can be removed.
196197
//
197198
// If we add one more overload for (Value, OptionList, ...), we can
198199
// also remove the DefaultFormatterForm definition for OptionList.
199-
template<typename T, typename TFormatter, typename THead, typename TTail, typename ...Ts>
200-
_always_inline auto printMultiple(const T &arg, const TFormatter &formatter, const Formatters::OptionList<THead, TTail> &list, const Ts &...args)
201-
//-> enable_if_valid_t<decltype(formatter.addOption(list.head)), size_t> {
202-
-> enable_if_valid_t<decltype(accepts_formatter(&formatter)), size_t> {
200+
template<
201+
typename T,
202+
typename TFormatter,
203+
typename THead,
204+
typename TTail,
205+
typename ...Ts,
206+
detail::enable_if_base_of<Print::Formatter, TFormatter>* = nullptr
207+
>
208+
_always_inline size_t printMultiple(const T &arg, const TFormatter &formatter, const Formatters::OptionList<THead, TTail> &list, const Ts &...args) {
203209
return printMultiple(arg, formatter, list.head, list.tail, args...);
204210
}
205211

206212
// Base case for the end of the OptionList
207-
template<typename T, typename TFormatter, typename THead, typename ...Ts>
208-
_always_inline auto printMultiple(const T &arg, const TFormatter &formatter, const Formatters::OptionList<THead, void> &list, const Ts &...args)
209-
//-> enable_if_valid_t<decltype(formatter.addOption(list.head)), size_t> {
210-
-> enable_if_valid_t<decltype(accepts_formatter(&formatter)), size_t> {
213+
template<
214+
typename T,
215+
typename TFormatter,
216+
typename THead,
217+
typename ...Ts,
218+
detail::enable_if_base_of<Print::Formatter, TFormatter>* = nullptr
219+
>
220+
_always_inline size_t printMultiple(const T &arg, const TFormatter &formatter, const Formatters::OptionList<THead, void> &list, const Ts &...args) {
211221
return printMultiple(arg, formatter, list.head, args...);
212222
}
213223
};
@@ -341,9 +351,6 @@ class DefaultFormatter : public Print::Formatter {
341351
/******************************************************************
342352
* OptionList */
343353

344-
//template<typename THead, typename TTail = void>
345-
//class OptionList;
346-
347354
template<typename THead, typename TTail>
348355
class OptionList : public Print::FormatterOption {
349356
public:
@@ -353,10 +360,12 @@ class OptionList : public Print::FormatterOption {
353360
constexpr OptionList(const THead& head, const TTail& tail) : head(head), tail(tail) { }
354361

355362
// Apply our contained options to a formatter
356-
template<typename TFormatter>
363+
template<
364+
typename TFormatter,
365+
detail::enable_if_base_of<Print::Formatter, TFormatter>* = nullptr
366+
>
357367
auto addToFormatter(const TFormatter& formatter) const
358-
-> enable_if_valid_t<decltype(accepts_formatter(&formatter)),
359-
decltype(formatter + this->head + this->tail)>
368+
-> decltype(formatter + this->head + this->tail)
360369
{
361370
return formatter + this->head + this->tail;
362371
}
@@ -366,10 +375,12 @@ class OptionList : public Print::FormatterOption {
366375

367376
public:
368377
// Append another option
369-
template<typename TOption>
378+
template<
379+
typename TOption,
380+
detail::enable_if_base_of<Print::FormatterOption, TOption>* = nullptr
381+
>
370382
constexpr auto operator +(const TOption& option) const
371-
-> enable_if_valid_t<decltype(accepts_option(&option)),
372-
OptionList<TOption, decltype(this->tail + option)>>
383+
-> OptionList<TOption, decltype(this->tail + option)>
373384
{
374385
return {this->head, this->tail + option};
375386
}
@@ -383,10 +394,12 @@ struct OptionList<THead, void> : public Print::FormatterOption {
383394
constexpr OptionList(const THead& head) : head(head) { }
384395

385396
// Apply our contained options to a formatter
386-
template<typename TFormatter>
397+
template<
398+
typename TFormatter,
399+
detail::enable_if_base_of<Print::Formatter, TFormatter>* = nullptr
400+
>
387401
constexpr auto addToFormatter(const TFormatter& formatter) const
388-
-> enable_if_valid_t<decltype(accepts_formatter(&formatter)),
389-
decltype(formatter + this->head)>
402+
-> decltype(formatter + this->head)
390403
{
391404
return formatter + this->head;
392405
}
@@ -396,10 +409,12 @@ struct OptionList<THead, void> : public Print::FormatterOption {
396409

397410
public:
398411
// Append another option
399-
template<typename TOption>
412+
template<
413+
typename TOption,
414+
detail::enable_if_base_of<Print::FormatterOption, TOption>* = nullptr
415+
>
400416
constexpr auto operator +(const TOption& option) const
401-
-> enable_if_valid_t<decltype(accepts_option(&option)),
402-
OptionList<THead, OptionList<TOption, void>>>
417+
-> OptionList<THead, OptionList<TOption, void>>
403418
{
404419
return {this->head, option};
405420
}
@@ -416,10 +431,14 @@ constexpr auto operator +(const TFormatter& formatter, const OptionList<THead, T
416431
}
417432

418433
// Start an OptionList by adding two options
419-
template<typename TOption1, typename TOption2>
434+
template<
435+
typename TOption1,
436+
typename TOption2,
437+
detail::enable_if_base_of<Print::FormatterOption, TOption1>* = nullptr
438+
detail::enable_if_base_of<Print::FormatterOption, TOption2>* = nullptr
439+
>
420440
constexpr auto operator+(const TOption1& first, const TOption2& second)
421-
-> enable_if_valid_t<decltype(accepts_option(&first), accepts_option(&second)),
422-
OptionList<TOption1, OptionList<TOption2, void>>>
441+
-> OptionList<TOption1, OptionList<TOption2, void>>
423442
{
424443
return {first, second};
425444
}
@@ -491,14 +510,10 @@ inline size_t Print::print( double n, int prec) { return print(n, FORMAT_
491510
// create them as wrapper classes, so you can match them directly. Then
492511
// unpack and repack the values inside whenever you work with them. This
493512
// avoids the need for these somewhat clunky checks using
494-
// enable_if_valid_t and accepts_formatter. Note that we cannot just
495-
// declare the parameters to be of the superclass type, since we need to
496-
// know the actual formatter/option class too.
497-
//
498-
// Idea: Expose accepts_option and accepts_formatter to debug problems
499-
// when formatters are not accepted (which typically leads to errors
500-
// that only say printTo(..., formatter/option) is not defined. A typical
501-
// error is no (or private) Formatter/FormatterOption base class.
513+
// enable_if_base_of. Declaring an option would then be a bit more
514+
// involved and less intuitive, though. Note that we cannot just declare
515+
// the parameters to be of the superclass type, since we need to know
516+
// the actual formatter/option class too.
502517
//
503518
// Idea: Because DefaultFormatter::printTo accesses options through
504519
// this, the compiler seems to force the options onto the stack and

0 commit comments

Comments
 (0)