HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
StrongParam< Tag, Basetype > Struct Template Reference

#include <strongparam.h>

Public Member Functions

 StrongParam (const Basetype &val)
 
 StrongParam (const StrongParam< Tag, Basetype > &val)=default
 
 operator const Basetype & () const noexcept
 

Detailed Description

template<typename Tag, typename Basetype>
struct StrongParam< Tag, Basetype >

StrongParam is used to construct an implementation of a derived type that lets you pass strongly typed parameters. It implicitly converts TO the basetype, but requires explicit conversion FROM the basetype.

The problem this is meant to address is that you may have a function that has multiple bool, int, or float paramters, particularly if they are adjacent in the call signature. This is extremely error prone. For example, suppose you have

void func (bool verbose, bool crazy, int apples, int oranges);

and then it is called:

func(true, false, 3, 8);

Is this correct, or does it harbor a bug? Your guess is as good as mine. In comparison, Python has a syntax that lets you name parameters, which looks like this:

func(verbose=true, crazy=false, apples=3, oranges=8);

But, unfortunately, no such syntax exists in C++. Maybe someday it will, but for now, we want something we can use to make the function call similarly clear. Like this:

func(Verbose(true), Crazy(false), Apples(3), Oranges(8));

and simultaneously for the following to be considered errors:

// Not allowed: bare bools and ints
func(true, false, 3, 8);

// Not allowed: getting the order wrong
func(Crazy(false), Verbose(true), Oranges(8), Apples(3));

Our solution is inspired by https://lists.llvm.org/pipermail/llvm-dev/2019-August/134302.html though we have simplified it quite a bit for our needs.

Example use 1: Use StrongParam to disambiguate parameters.

// Use macro to generate the new types
OIIO_STRONG_PARAM_TYPE(Verbose, bool);
OIIO_STRONG_PARAM_TYPE(Crazy, bool);

bool
compute (Verbose a, Crazy b)
{
    return a | b;
}

Example 2: Use StrongParam to disambiguate two floats, a poor person's implementation of units:

Error prone: speed(float,float) // which is first, meters or seconds? Unambiguous: speed(Meters,Seconds)

OIIO_STRONG_PARAM_TYPE(Meters, float);
OIIO_STRONG_PARAM_TYPE(Seconds, float);

float
speed (Meters a, Seconds b)
{
    return a / b;
}

Note that the fancy strong type is for declaration purposes. Any time you use it in the function, it implicitly converts to the underlying base type.

As an alternative to OIIO_STRONG_TYPE(Meters, float), you may also use this notation (if you find it more pleasing):

using Meters = StrongParam<struct MetersTag, float>;

The MetersTag struct need not be defined anywhere, it just needs to be a unique name.

Definition at line 95 of file strongparam.h.

Constructor & Destructor Documentation

template<typename Tag, typename Basetype>
StrongParam< Tag, Basetype >::StrongParam ( const Basetype &  val)
inlineexplicit

Definition at line 97 of file strongparam.h.

template<typename Tag, typename Basetype>
StrongParam< Tag, Basetype >::StrongParam ( const StrongParam< Tag, Basetype > &  val)
default

Member Function Documentation

template<typename Tag, typename Basetype>
StrongParam< Tag, Basetype >::operator const Basetype & ( ) const
inlinenoexcept

Definition at line 106 of file strongparam.h.


The documentation for this struct was generated from the following file: