12

I am currently using boost.parameter with some factory functions and compile times are getting prohibitive.

currently I have a common pattern like this:

auto thing = makeThing(property1 = foo::bar, "myThing"_thingName);

where makeThing has like 30 parameters, most of them with defaults. I would like to preserve the "named parameter like" syntax and the ability to match parameters by type not by position.

How can I get better compilation speed without changing the syntax at the call site of my factory?

note: Judging by the difference between boost.MPL speed and say brigand speed it seems to me that there should be at least an order of magnitude improvement in compile time if modern meta programming techniques were used in a boost.parameter equivalent.

update: here is a abridged example of what exactly I'm doing: in a bare metal embedded context I have different peripherals abstracted as complex templated classes following the policy based class design idiom. Each class takes a lot of configuration info at compile time and uses only the required functionality (can't rely on the optimizer to strip out unused stuff because all the SFR interactions are observable, therefore volatile so it is not allowed).

These policy based classes are super ugly for the user to configure and most embedded users run away screaming if they see a < in the public interface so I use boost.parameter to make a sexy factory to which they can pass all their type encoded wishes (like in hana style) and I generate the class as a local static hooking it up to required ISRs and passing back a handle.

namespace usb
{
    BOOST_PARAMETER_NAME(hw)
    BOOST_PARAMETER_NAME(vid)
    BOOST_PARAMETER_NAME(pid)
    BOOST_PARAMETER_NAME(device_class)
    BOOST_PARAMETER_NAME(max_packet_ep0)
    BOOST_PARAMETER_NAME(max_packet)
    BOOST_PARAMETER_NAME(packet_pool_size)
    BOOST_PARAMETER_NAME(device_description)
    BOOST_PARAMETER_NAME(device_calss_description)
    BOOST_PARAMETER_NAME(can_power_down)
    BOOST_PARAMETER_NAME(stall_supported)
    BOOST_PARAMETER_NAME(setup_packet_timeout)
    //...

BOOST_PARAMETER_FUNCTION(
    (usb_handle),
    make,    

    tag,                 

    (required(hw, *)) 

    (optional
    (vid, *, 0x6001_ci)
        (pid, *, 0x1234_ci)
        (device_class, *, cdc_class{})
        (max_packet_ep0, *, 8_ci)
        (max_packet, *, 64_ci)
        (packet_pool_size, *, 12_ci)
        (device_description, *, "")
        (device_calss_description, *, "")
        (can_power_down, *, 0_ci)
        (stall_supported, *, 0_ci)
        (setup_packet_timeout, *, 100_ci)
        )
)
{
    // makes a local static policy based class taylored at compile time 
    // to support only the specified features
    return{};  //returns a handle to the local static
}
}

Most factories have 10-25 parameters and preprocessor time seems to be the killer. It takes like 1-5 seconds per factory regardless of whether the user actually calls the function or not.

update 2: well the bounty has ended so it looks like there is no solution. If I find time I will write a boost.parameter replacement and link it here. It would also be nice to make the return type of the named parameter function depend on the input types in order to get closer to boost.hana style semantics.

odinthenerd
  • 5,422
  • 1
  • 32
  • 61
  • 2
    Clear offtopic, sorry. – SergeyA Jun 03 '16 at 14:02
  • 1
    Straight from the description. *Questions asking to recommend ... a library...* – SergeyA Jun 03 '16 at 14:18
  • Any solution that doesn't involve writing source code is off topic. You can change your compiler, which is a recommendation question; you can change your hardware, which is a superuser question; you can use another implementation, which is a recommendation question; or you can write code, which alone is on-topic here. – user207421 Jun 04 '16 at 11:19
  • 5
    I think this is a legitimate and interesting question, hence my upvote: In modern C++ questions about the compilation are very relevant since at compilation actual things are calculated, processed. boost.parameter is not any library, because being part of boost it is an almost official standard library (as a matter of fact, many boost libraries do become official standards) and I think the problem/solution the OP requests may be independent of the compiler, platform. – TheCppZoo Jun 06 '16 at 21:01
  • 2
    Please make your question more clear with examples of the factories and what they manufacture, why do they have so many arguments. I can't give you an answer because I don't know exactly what you are asking, however, I have solved similar compilation bottlenecks – TheCppZoo Jun 06 '16 at 21:07
  • 3
    My suggestion is a fluent API instead of the parameter syntax. C++ doesn't support it natively, so don't contort it if you don't need to. It's a nice exercise in intellectual masturbation but beyond that, not really helpful. – Sohail Jun 12 '16 at 22:57

1 Answers1

1

You can implement the via global constexpr static objects, like this:

struct init_ 
{  
    my_class operator()(int i) {return i;} 
    my_class operator= (int i) {return i;} 
};
consexpr static init_ init;

//make function
template<typename ...Args>
thingy make(Args&&...args);


auto x = make(init=42);

You might need to add an constexpr ctor to init_. You can then use boost.fusion or boost.hana to get a for_each for the sequence and initialize your type.

struct thingy { int x;};

struct x_init 
{
    int init;
    x_init (int i) : init(i) {};
    void operator()(thingy & t)
    { t.x = init;}
};

struct x_
{
    constexpr x_() {};
    x_init operator()(int i) const {return i;}
    x_init operator= (int i) const {return i;}
};
constexpr static x_ x;

template<typename ...Args>
thingy make(Args &&...)
{
     thingy t;
     auto vec = boost::fusion::make_vector(std::forward<Args>(args)...);
     boost::fusion::for_each(vec, [t](auto & init){init(t);});
}

auto t = make(x=42);

Boost.Process actually uses that, if you look into my repository on github, you find a rather complicated version of that.