Sign in to follow this  
Juliean

"Reflect" default function parameter value

Recommended Posts

Hello,

 

is it entirely possible to get 1) whether a function paramter has a default value and 2) what that value is?

 

Reason for this is that I'm writing an automatic function binding libary for my visual scripting system, so that I don't have to write the function declaration & do the paramter unpacking myself for every function I use there. This is working so far using a heavy load of template metaprogramming, which allows me to get the type of a certain function parameter:

/***************************
* getVariadicType
*
* allows access to the type of a certain variadic parameter
***************************/

template <size_t Index, typename... Types>
struct getVariadicType;

template <typename Type, typename... Types>
struct getVariadicType<0, Type, Types...>
{
    using type = Type;
};

template <size_t Index, typename Type, typename... Types>
struct getVariadicType<Index, Type, Types...>
{
    using type = typename getVariadicType<Index - 1, Types...>::type;
};

/***************************
* FunctionReflector
*
* takes a function pointer of any type, and allows processing its parameters via a Visitor class.
***************************/

template<typename Visitor, typename Return, typename... Args>
class FunctionReflector
{
    static const size_t NUM_ARGS = sizeof...(Args);
public:

    typedef Return(*FuncPointer)(Args...);

    FunctionReflector(FuncPointer pFunction) : m_pFunction(pFunction)
    {
    }

    void Visit(const Visitor& visitor) const
    {
        return HelpCall<NUM_ARGS, NUM_ARGS>::Call(m_pFunction, visitor);
    }

private:


    /***************************
    * HelpCall
    *
    * Helper class for unpacking the variadic template args
    ***************************/

    template<int Number, int Count, typename... CallArgs>
    struct HelpCall
    {
        using ElementType = typename getVariadicType<Count - Number, Args...>::type;

        static void Call(FuncPointer function, const Visitor& visitor)
        {
            visitor.Visit<ElementType, Count - Number>();

            HelpCall<Number - 1, Count>::Call(function, visitor);
        }
    };

    template<int Count>
    struct HelpCall<0, Count>
    {
        static void Call(FuncPointer function, const Visitor& visitor)
        {
        }
    };

    FuncPointer m_pFunction;
};

Now I don't expect anyone to understand that template mindfuck, its just there if anyone needs a reference to what is possible in the current system. But it basically boils down to a Visit-method of a Visitor class being called for each function parameter:

struct DeclarationGenerator
{
    DeclarationGenerator(Declaration::EntryVector& vEntries) : m_pEntries(&vEntries)
    {
    }

    template<typename Type, size_t Element>
    void Visit(void) const // this is called for each function parameter, Type is the parameter type, Element is the number of element
    {
        // add a new entry to the function declaration vector
        m_pEntries->emplace_back(L"Test", core::generateTypeId<Type>(), core::isArray<Type>::value);
    }

private:

    Declaration::EntryVector* m_pEntries;
};

So only problem now is that, unlike before, I cannot supply a custom default value anymore. This would have been done by simply putting the value in the vector pushback instead, when I was creating the declaration manually:

m_pEntries->emplace_back(L"Test", 12); // default value for this parameter is "12", type is "int"

I think it should be clear what I'm looking for now: A "simple" check for default parameter presence like that:

void function(int arg1 = 10, int arg2)
{
}

std::has_default_parameter<function, 0>::value; // = true
std::has_default_parameter<function, 1>::value; // = false

std::default_parameter_value<function, 0>::value; // 10
std::default_parameter_value<function, 1>::value; // eigther undefined or 0 as default int value

eigther via the standard libary or some custom variant... any ideas? Is this even possible? If it is not, do you have any idea for how I can supply default parameters to my function declaration, while still handling the declaration generation automatically? Thanks for any help in advance!

Edited by Juliean

Share this post


Link to post
Share on other sites

I'm reading that over, and I am forced to ask:  WHY?

 

What are you doing that you need to handle "declaration generation automatically", whatever that is?

 

 

 

C++ usually handles default parameters through polymorphism, either implicitly through providing a value in the declaration, or explicitly by wrapping it in a polymorphic stub that you can place in your header to be inlined.

 

It effectively generates the same thing as the explicit method of doing the same thing:

int SomeFunc() { return SomeFunc(NULL, "Default", true); }
int SomeFunc(Callback c) { return SomeFunc(c, "Default", true); }
int SomeFunc(Callback c, char* message) { return SomeFunc(c, message, true); }
int SomeFunc(Callback c, char* message, bool flag); // the 'real' function declaration

What are you attempting to do with optional parameters that polymorphism does not work for you?

Share this post


Link to post
Share on other sites
As to the why, I thought I gave enought background information, but seems I was wrong.

As I already said I am doing a function registration system for my visual scripting system (for visual reference, see UE4s Blueprints). This "Declaration" class stores the information needed to reflect a functions parameter types, names and, as asked here, default values at runtime and by the visual scripting system.

Now the problem is that I've been writing those declarations by myself for every function I register, which is a lot of unnecessary work. As I said, I already managed to automatically generate the declaration information for a functions parameters type, but default values are what throw me off.

To go a little more into detail why this is needed: In a visual scripting system like mine, a function node that is placed in the graph has each parameter exposed as a text input box. And this is where default values come into play: being able to assign a default value for often used vales reduces a significant amount of work.

What you suggested doesn't work in such a system like I described, as first of all there are no function overloads with the same function name, also its not about offering optional parameters, but just filling put most-used default values for you in the interface.

I hope I,ve been more clear now and the " why " is answered. Any more thoughts based on that?

Share this post


Link to post
Share on other sites

is it entirely possible to get 1) whether a function paramter has a default value and 2) what that value is?


1) No
2) No

C++ offers no real reflection capabilities at all, currently. Any reflection mechanism in C++ is basically built around type deduction tric,s, SFINAE detection of members with specific signature patterns, redeclaring members manually, and manually resolving overload sets.

Since all a default parameter does is add an overload, you must manually resolve its existence. And there's no way at all to extract the default value.

The various reflection proposals in flight for C++17 or later may or may not suit your needs. I'd suggest getting involved at isocpp.org if you feel you have a strong use case.

Systems like UE4's blueprints rely on an external reflection system that parses the code separately from the compiler (or as a compiler plugin when you're using GCC or Clang) to extract information rather than trying to build the mechanism with the C++ language itself. That's basically the only way to do what you're trying to do (avoid redeclarations for reflection) in C++ today.

Share this post


Link to post
Share on other sites


To go a little more into detail why this is needed: In a visual scripting system like mine, a function node that is placed in the graph has each parameter exposed as a text input box. And this is where default values come into play: being able to assign a default value for often used vales reduces a significant amount of work.

Sounds like you are looking for a metadata tag.

 

As Sean just pointed out, C++ does not offer such a thing. 

 

I think I'd go with a quick header parse tool, sticking the items in a comment directly above the source file.  I'd stick with established conventions for those so you can leverage existing block comment extraction tools.  

 

For example you might use a function block heading comment with a markup in the form:  @param <name> <default-value> <text description>. Then your tool can extract it and find all the helpful information for the default value and the user-friendly help in one place.

Share this post


Link to post
Share on other sites


1) No
2) No

C++ offers no real reflection capabilities at all, currently. Any reflection mechanism in C++ is basically built around type deduction tric,s, SFINAE detection of members with specific signature patterns, redeclaring members manually, and manually resolving overload sets.

 

I already knew that C++ lacks even the most basic things about reflection, thats why I've had to come up with my custom type system that is used as base for this after all. But I still had hope that there was some mechanism for this, since there is stuff like std::is_const, std::is_enum, etc...

 


Since all a default parameter does is add an overload, you must manually resolve its existence. And there's no way at all to extract the default value.

 

Didn't really know that, thanks for clarification.

 


The various reflection proposals in flight for C++17 or later may or may not suit your needs. I'd suggest getting involved at isocpp.org if you feel you have a strong use case.

 

Sounds interesting, but I don't think this will arive in time for me to be useful. As I require the system proposed by me for my reworked asset-system right now (which I didn't mention for simplicity), I don't think I can quite wait for C++17 to hit the store

 


Systems like UE4's blueprints rely on an external reflection system that parses the code separately from the compiler (or as a compiler plugin when you're using GCC or Clang) to extract information rather than trying to build the mechanism with the C++ language itself. That's basically the only way to do what you're trying to do (avoid redeclarations for reflection) in C++ today.

 

Having worked with UE4 for some time now, I already knew kind of how they do things, but I hoped I could get around this some way shape or form. But quess thats my only way... *sight* one more mammut project on the list. Thanks for your input anyways!

 

@frob:

 

Yeah, I think thats quite what I need. Initially I didn't know if I like the usage of comments for this though, since this would also require more explicit work on the users side. But after thinking about it, I do belive that this is really the only viable way for embedding information like non-parameter-confirm names (think of a parameter called vTexturePtrs, but you want to call it TexturePointers for the visual scripting), and especially descriptions (which I've seen UE4 making heavy use of, and being really helpful most of the time). So I quess this is a really good way for doing this. Thanks for the suggestion, quess I'll have a lot of work to do getting my own header-parser/compiler going. Should pay off in the end though.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this