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

Skip to content

Commit 3913a2b

Browse files
WIP
1 parent 9e13289 commit 3913a2b

File tree

1 file changed

+66
-22
lines changed

1 file changed

+66
-22
lines changed

cores/arduino/Print.h

Lines changed: 66 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -220,26 +220,6 @@ void accepts_option(const Print::FormatterOption*);
220220
// cluttering the global namespace. Could be removed if needed.
221221
namespace Formatters {
222222

223-
224-
// TODO: Do we really need a FormatterOption base class? Without it,
225-
// options can be POD, not needing a constructor. With it, we can
226-
// prevent accidentally treating things as options which are not, but if
227-
// we already check a Formatter base class, we can also require that
228-
// Formatters do not define nonsensical addOption methods (even more,
229-
// without an explicit FormatterOption, Formatters can even use
230-
// non-class types as options if they want).
231-
// TODO: Where to define the "default formatter" for an option? Now, it
232-
// is our superclass, but it might just as well be defined with a using
233-
// directive directly here. Or perhaps it should be a method (this
234-
// might be problematic, since the DefaultFormatter type is incomplete
235-
// at this point). One completely different approach would be a
236-
// DefaultFormatterFor template, which gets specialized, but this
237-
// probably has the problem that once it is instantiated, you can no
238-
// longer add to it. Using specializations does allow defining a default
239-
// formatter for a type/option combination (allowing reuse of e.g. HEX
240-
// for custom types) or for just a type (allowing default formatting of
241-
// custom types).
242-
243223
class DefaultFormatter : public Print::Formatter {
244224
public:
245225
// Common base class for our options
@@ -528,12 +508,61 @@ inline size_t Print::print( double n, int prec) { return print(n, FORMAT_
528508
// accept the DefaultFormatter instance by-value, and a generic
529509
// non-static printTo could be added that forwards all calls to the
530510
// static versions. Doing this in DefaultFormatter instead of coding
531-
// this in Print/PrintHelper, leaves control over by-value/by-ref at the
511+
// this in Print, leaves control over by-value/by-ref at the
532512
// formatter author and probably gives the cleanest Formatter interface
533-
// (an alternative would to just have PrintHelper call a static printTo,
513+
// (an alternative would to just have Print call a static printTo,
534514
// in which case the formatter could still decide to accept the
535515
// formatter instance by reference or by value).
536516
//
517+
// Limitation: Default formatters for a value type and/or option type
518+
// are specified using overloads of the DefaultFormatterFor function.
519+
// You can use templates to get wildcard overloads (e.g. specify a
520+
// default formatter for all options passed to a specific type, or a
521+
// default formatter for any type combined with a specific formatter).
522+
//
523+
// If both overloads exist, this might cause ambiguity. e.g. when you
524+
// have a (FooT value, *) overload and a (*, BarOption) overload, doing
525+
// print(FooT(), BarOption()) is ambiguous. Usually, this will also be
526+
// invalid (the formatter belonging to BarOption will likely not know
527+
// how to print a FooT anyway). There might be cases where it is not,
528+
// but it is not clear which of the two to favor in this case. If
529+
// needed, some kind of priority tag argument could later be added, with
530+
// a fallback to the regular tag-less version). Also, even in the
531+
// invalid case, the "ambiguous" error message is not so nice.
532+
//
533+
// Note that the current approach of using a formatter-specific
534+
// superclass (e.g. DefaultFormatter::FormatterOption) between the
535+
// actual option class and Print::FormatterOption already makes
536+
// overloads that use it (and thus need parent class conversion) less
537+
// specific than templated overloads (which match their arguments
538+
// exactly). This resolves the ambiguity, but I'm not sure if this is
539+
// the right resolution.
540+
541+
// Limitation: DefaultFormatterFor relies on argument-dependent-lookup
542+
// (ADL) to work properly. Normally, when a function is called, only
543+
// overloads defined up to where the function call is defined are
544+
// considered (e.g. the call the DefaultFormatterFor in Print.h). In
545+
// this case, we want to allow defining more overloads later. We can
546+
// make this work because DefaultFormatterFor is only called from
547+
// template functions, and for those ADL happens at template
548+
// *instantiation time*, rather than *definition time*.
549+
//
550+
// ADL happens for all types in a namespace (including the root
551+
// namespace). Notably, this means ADL happens for class types (options
552+
// and custom value types), but not for native types (e.g. int does not
553+
// live in a namespace). In practice, this means that replacing the
554+
// default formatter for a native type (without any options) is not
555+
// possible, since the reference to e.g. DefaultFormatterFor(int) is
556+
// looked up at template definition time, not instantiation time.
557+
//
558+
// Two possible workarounds for this would be to add a wrapper class
559+
// around values before passing them to DefaultFormatterFor, or adding
560+
// an unused dummy argument that forces ADL. The latter is probably
561+
// easiest, and if the dummy argument is called NoOption and is the
562+
// second argument, that might actually be fairly easy to work with as
563+
// well.
564+
//
565+
//
537566
// Mail
538567
//
539568
// For adding options to formatters, I'm using the overloaded addition
@@ -556,3 +585,18 @@ inline size_t Print::print( double n, int prec) { return print(n, FORMAT_
556585
// counts characters written for alignment?).
557586
//
558587
// Compatibility with C++ <= 11
588+
//
589+
// ADL needed for DefaultFormatterFor - no primitive types
590+
//
591+
// TODO: Suggest workaround for ADL/primitive types using wrapper type
592+
// (not in mail). Probably requires priority tagging to try wrapped type
593+
// before unwrapped type, or some kind of primitive/nonprimitive
594+
// detection for SFINAE. Or add Dummy argument, to force (meaningless)
595+
// ADL.
596+
//
597+
// TODO: See if accepts_formatter can be called in default template
598+
// argument as well (these are filled in after deduction, right? We only
599+
// depend on the type, not the argument value)?
600+
//
601+
// TODO: Use NoOption dummy argument to DefaultFormatterFor to force
602+
// ADL?

0 commit comments

Comments
 (0)