Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

How to slove this error when using enable_if: "no type named ‘type’ in ‘struct std::enable_if<false, void>’"

Ask Question

I want to invoke pushArg() method with different kinds of the type of T .

Here is the relate code snippet:

//test.hpp
struct Demo {int a};
typedef int (*CALL_CFunction)(struct Demo* );
classs Ctx
    /*push bool */
    template <typename T, 
              typename std::enable_if<std::is_integral<T>::value>::type* = nullptr,
              typename std::enable_if<std::is_same<T, bool>::value>::type* = nullptr>
    int pushArg(T& val)
        std::std << "push bool" <<std::endl;  
        return 0;
    /*push lua_CFunction*/
    template <typename T, 
          typename std::enable_if<std::is_pointer<T>::value>::type* = nullptr,
          typename std::enable_if<std::is_same<CALL_CFunction, T>::value>::type* = nullptr>
    int pushArg(T& val)
        std::cout << "push function" << std::endl;
        return 0;

The function to call pushArg():

int foo(Struct Demo *) {return 0;}
Ctx ctx;
ctx.pushArg(foo);

Here are the error meessages:

  test.cpp:36:22: error: no matching function for call to ‘ctx::pushArg(int (&)(lua_State*))’
      pCtx->pushArg(foo);
    In file included from test.cpp:1:0:
    test.hpp:131:9: note: candidate: template<class T, typename std::enable_if<std::is_integral<_Tp>::value>::type* <anonymous>, typename std::enable_if<std::is_same<T, bool>::value>::type* <anonymous> > int ctx::pushLuaArg(T&)
         int pushLuaArg(T& val)
    test.hpp:131:9: note:   template argument deduction/substitution failed:
    test.hpp:129:76: error: no type named ‘type’ in ‘struct std::enable_if<false, void>’
               typename std::enable_if<std::is_integral<T>::value>::type* = nullptr,

The parameter val of pushArg is declared as pass-by-reference, then given ctx.pushArg(foo);, function-to-pointer decay won't happen, and T is deduced as function type, i.e. int (Demo*). For the 2nd overload, both std::is_pointer<T>::value and std::is_same<CALL_CFunction, T>::value yield false.

For std::is_pointer, you can use std::is_function instead but it seems redundent. Just std::is_same is enough. (If std::is_same<CALL_CFunction, T*>::value gives true then std::is_function<T>::value will be true too.) E.g.

template <typename T, 
          typename std::enable_if<std::is_same<CALL_CFunction, T*>::value>::type* = nullptr>
//                                                              ^
int pushArg(T& val)
                Why is std::is_same<lua_CFunction, T*>::value, not std::is_same<lua_CFunction, T>::value? Could you please explain that in more detail for me?
– John
                Dec 15, 2020 at 3:15
                @John Function type, and function pointer type are not the same thing. They have to match when being compared by std::is_same.
– songyuanyao
                Dec 15, 2020 at 3:18
        

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.