Search code examples
c++templatesfunction-pointersvariadic-functionspointer-to-member

Getting the correct type information for a function returning a function-pointer that uses variadic templates


I have a variadic function defined within class Foo

AddCodeChunkInner(Type, DerivativeStatus, bInlined, Format, args...);

And I am trying to write a function that returns its function pointer

static auto getAddCodeChunkInner(){return &Foo::AddCodeChunkInner;}

However I'm getting an error stating that it "cannot deduce type for 'auto' from 'overloaded-function'.

I believe the solution should look something like this:

template <typename... Args>
static auto getAddCodeChunkInner(Args...) -> decltype(int32 (Foo::*) (EMaterialValueType Type, EDerivativeStatus DerivativeStatus, bool bInlined, const TCHAR* Format, ...))

I'm struggling a little bit to find the correct syntax here though. I have the general idea, but my knowledge of templates is a bit lacking

minimum reproducible example:

class FHLSLMaterialTranslator : public FMaterialCompiler
{
int32 AddCodeChunkInner(uint64 Hash, const TCHAR* FormattedCode, EMaterialValueType Type, EDerivativeStatus DerivativeStatus, bool bInlined);
}

int32 FHLSLMaterialTranslator::AddCodeChunkInner(uint64 Hash, const TCHAR* FormattedCode, EMaterialValueType Type, EDerivativeStatus DerivativeStatus, bool bInlined)
{
    return 1;
}

class myHLSLMaterialTranslator : public FHLSLMaterialTranslator
{
public:
    static auto getAddCodeChunkInner(){return &FHLSLMaterialTranslator::AddCodeChunkInner;}
};

Solution

  • Whatever your problem is, it's nothing to do with the function being variadic or the return type of your function being inferred. The following code compiles with no problem on gcc, clang, and MSVC:

    struct S
    {
      void f(int, ...) { }
    };
    
    static auto getF() { return &S::f; }
    

    Given the error message you're describing, it sounds like maybe the problem is instead that you have more than one function in Foo called AddCodeChunkInner. If that's the case, you can explicitly specify which overload you're talking about by doing a cast which the desired overload will be the best match for:

    struct T
    {
      void g(int) { }
      void g(int, ...) { }
    };
    
    static auto getG1() { return static_cast<void(T::*)(int)>(&T::g); }
    
    static auto getG2() { return static_cast<void(T::*)(int, ...)>(&T::g); }