Fhiclcpp types in detail » History » Version 33

« Previous - Version 33/56 (diff) - Next » - Current version
Kyle Knoepfel, 11/17/2015 01:29 PM

fhiclcpp types in detail

Parameter constructors

General rules

For each of the fhiclcpp types, the following rules apply:
  • The Name argument is required.
  • If there is more than one argument, the Name argument must be first in the list.
  • If there are three arguments, the relative order of the Comment argument and default-value argument is not important.
    Atom<int> val { Name("val"), Comment("Some parameter"), 9 }; // is equivalent to
    Atom<int> val { Name("val"), 9, Comment("Some parameter") };
  • Neither the Table<T> parameter nor any of the Optional* parameters support a default value.


Atom<int> var { Name("var") };
Atom<int> var { Name("var"), 9 };
Atom<int> var { Name("var"), Comment("A parameter description") };
Atom<int> var { Name("var"), Comment("A parameter description"), 9 };


OptionalAtom<int> var { Name("var") };
OptionalAtom<int> var { Name("var"), Comment("A parameter description") };


This class template is used for unbounded sequences. See the two caveats below.

OptionalSequence<int> seq { Name("seq") };
OptionalSequence<int> seq { Name("seq"), Comment("A sequence") };


This class template is used for sequences of a specific length, known at compile time.

OptionalSequence<int,3u> seq { Name("seq") };
OptionalSequence<int,3u> seq { Name("seq"), Comment("A sequence") };


OptionalTable<T> config { Name("config") };
OptionalTable<T> config { Name("config"), Comment("This describes the table") };


OptionalTuple<string,bool> tuple { Name("tuple") };
OptionalTuple<string,bool> tuple { Name("tuple"), Comment("A tuple") };


This class template is used for unbounded sequences. See the two caveats below.

Sequence<int> seq { Name("seq") };
Sequence<int> seq { Name("seq"), Comment("A sequence") };
Sequence<int> seq { Name("seq"), Sequence<int>{ 4, 5, 6, 7 } };
Sequence<int> seq { Name("seq"), { 4, 5, 6, 7 } };
Sequence<int> seq { Name("seq"), Comment("A sequence"), Sequence<int>{ 4, 5, 6, 7 } };
Sequence<int> seq { Name("seq"), Comment("A sequence"), { 4, 5, 6, 7 } };


Due to the implementation details of the unbounded sequence, the following:

Sequence<int> seq { Name("seq"), Sequence<int>{} }; // Don't do this.

does not represent an empty sequence. If you would like an empty sequence as a default value, use the following:

Sequence<int> seq { Name("seq"), Sequence<int>::make_empty() };

Precaution regarding narrowing conversions and std::initializer_list objects

The following configuration will trigger a compilation warning:

Sequence<int> seq1 { Name("seq1"), Sequence<int>{ 1, 2.4e-4 } };
Sequence<int> seq2 { Name("seq2"), { 1, 2.4e-4 } };

that looks similar to this:

warning: narrowing conversion of ‘2.4000000000000001e-4’ from ‘double’ to ‘int’ inside { } [-Wnarrowing]

For build systems that convert compile-time warnings to errors, this will result in a build failure. The warning results from the nature of an std::initializer_list object, signified by '{1, 2.4e-4}', which is used to initialize the sequence objects. For std::initializer_list objects, narrowing conversions are not allowed--that is, converting a double to an int is an example of narrowing that results in loss of information. This is the most likely example of where you may find a narrowing conversion.


This class template is used for sequences of a specific length, known at compile time.

Sequence<int,3u> seq { Name("seq") };
Sequence<int,3u> seq { Name("seq"), Comment("A sequence") };
Sequence<int,3u> seq { Name("seq"), Sequence<int,3u>{ 4, 5, 6 } };
Sequence<int,3u> seq { Name("seq"), { 4, 5, 6 } };
Sequence<int,3u> seq { Name("seq"), Comment("A sequence"), Sequence<int,3u>{ 4, 5, 6 } };
Sequence<int,3u> seq { Name("seq"), Comment("A sequence"), { 4, 5, 6 } };

The warning regarding narrowing conversions above applies for bounded sequences as well.


Table<T> config { Name("config") };
Table<T> config { Name("config"), Comment("This describes the table") };


Tuple<string,bool> tuple { Name("tuple") };
Tuple<string,bool> tuple { Name("tuple"), Comment("A tuple") };
Tuple<string,bool> tuple { Name("tuple"), Tuple<string,bool>{"explicit?", true} };
Tuple<string,bool> tuple { Name("tuple"), {"compact?", true } };
Tuple<string,bool> tuple { Name("tuple"), Comment("A tuple"), Tuple<string,bool>{ "Particle physics is neat.", true } };
Tuple<string,bool> tuple { Name("tuple"), Comment("A tuple"), { "This is false", false } };

Return types

fhiclcpp parameter Function call Return type
Simple fhiclcpp parameters
Atom<std::string> label; label() std::string const&
Sequence<int> counts; counts() std::vector<int>
counts(1) int
Sequence<double, 3u> point; point() std::array<double, 3u>
point(0) double
Tuple<std::string, double> assoc; assoc() std::tuple<std::string, double>
assoc.get<0>() std::string
assoc.get<double>() double
Table<Config> config; config() Config const&
Nested fhiclcpp parameters
Sequence< Sequence<int> > datasets; datasets() std::vector< std::vector<int> >
datasets(17) std::vector<int>
Sequence< Sequence<int>, 2u > twoDatasets; twoDatasets() std::array< std::vector<int>, 2u >
twoDatasets(1) std::vector<int>
Sequence< Sequence<int, 2u> > intPairs; intPairs() std::vector< std::array<int, 2u> >
intPairs(42) std::array<int, 2u>
Sequence< Tuple<std::string, int, bool> > triplets; triplets() std::vector< std::tuple<std::string, int, bool> >
triplets(3) std::tuple<std::string, int, bool>
Sequence< Table<Config> > manyConfigTables; manyConfigTables() std::vector< Config >
manyConfigTables(6) Config const&
Tuple< std::string, Table<Config> > configAssoc; configAssoc() std::tuple< std::string, Config >
configAssoc.get<0>() std::string
configAssoc.get<std::string>() std::string
configAssoc.get<1>() Config
configAssoc.get< Table<Config> >() Config
Tuple< Tuple<std::string,bool>, Sequence<int> > awkward; awkward() std::tuple< std::tuple<std::string, bool>, std::vector<int> >
awkward.get<0>() std::tuple<std::string,bool>
awkward.get<1>() std::vector<int>

Additional functions for Table<T>

The Table template offers a few extra functions that the user can call:

fhicl::ParameterSet const& get_PSet() const;

void print_allowed_configuration(std::ostream& os,
                                 std::string const& tab = std::string(3,' ') ) const;

// Expert-level functions
void validate_ParameterSet(fhicl::ParameterSet const& pset,
                           std::set<std::string> const& keysToIgnore = {} );


A call to this function returns a const reference to the ParameterSet object that was used to fill the values of the individual Table members. This is helpful for users who need to interact with the ParameterSet object itself.


For any Table<Config> object, print_allowed_configuration will fill a user-supplied std::ostream object with the allowed configuration as defined by the Config struct. The optional second argument specifies the number of spaces per indentation. The default is 3 spaces but is, of course, user-configurable.

[ N.B. The following function should not normally be invoked by users. It is meant to be called only in contexts outside of art. Please consult for guidance.]

validate_ParameterSet (expert)

This function is intended for experts who need to validate the pset object themselves. The keysToIgnore variable represents a set of keys for which the validation step will ignore. The validation function will ignore any nested keys as well--i.e. if a user specifies an ignorable key as table1, the (e.g.) table1.someAtom key would be ignored in addition to just the table1 name. An indexed parameter (e.g.) seq[1] is considered a nested parameter of its parent seq. Providing or not providing the ignorable key in a configuration will lead to no error upon validation of the ParameterSet.

Should the validation step fail, an exception is thrown of type fhicl::detail::validationException. This behavior is not currently configurable.

Common parameter accessors

Each of the fhiclcpp types has the following accessors:

std::string key()            const;
std::string name()           const;
std::string comment()        const;
bool        has_default()    const;
bool        is_optional()    const;
par_type    parameter_type() const;

To call these functions, the difference in syntax is crucial:

Atom<int> val { Name("val") };

auto key1 = val.key();   //   correct
auto key2 = val().key(); // ! compile-time ERROR - 'val()' is an int, which has no accessor called 'key()' 


A call to key() returns the full key, including all enclosing tables. For example, consider a module that is designed to allow the following configuration:

pset: {
  list: [ { particle: electron },
          { particle: muon } ]
For a suitably declared set of fhiclcpp parameters, the returned key corresponding to "muon" would be pset.list[1].particle.


The name is the most-nested name in the key. For the above "muon" parameter, a key of pset.list[1].particle has a corresponding name of particle. If the parameter in question were pset.list[1], the name would be1 list[1].

1 Technically, this is inaccurate -- sequence elements do not have names. However, for the sake of parameter identification, a sequence element has a name whose value is the sequence name with the appropriate sequence element index/indices appended.


Returns the comment supplied as the string literal in (e.g.) Comment("Here is the comment"). If no Comment argument is provided in the fhiclcpp parameter constructor, a call to this function returns an empty string.


Returns true or false depending on whether the user supplied a default value for the parameter.


Returns true or false depending on whether the parameter is of an Optional* fhiclcpp type.


Returns an enumeration value based on the parameter type:

enum class par_type {
  ATOM,        // (Optional)Atom<T>
  TABLE,       // (Optional)Table<T>
  SEQ_VECTOR,  // (Optional)Sequence<T>
  SEQ_ARRAY,   // (Optional)Sequence<T,std::size_t>
  TUPLE,       // (Optional)Tuple<T...>
  NTYPES       // Signifies invalid parameter