CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 8 of 8
  1. #1
    Join Date
    Jul 2002
    Location
    Portsmouth. United Kingdom
    Posts
    2,727

    Question Template specialisation error

    Does anyone know if there's a way to make this specialisation work?
    I have a feeling that it is not possible to do what I want. Can anyone prove me wrong?

    The previous incarnation of the original code passes the member function pointer as a parameter in the constructor.
    With this code I am attempting to get the address at compile time.

    Code:
      template <typename TObject, typename TParameter, void(TObject::*p_function)(TParameter)>
      class function
      {
      public:
    
        function(TObject& object)
          : p_object(&object)
        {
        }
    
        void operator ()(TParameter data)
        {
          // Call the object's member function with the data.
          (p_object->*p_function)(data);
        }
    
      private:
    
        TObject* p_object;
      };
    
      // Specialisation
      template <typename TObject, void(TObject::*p_function)(void)>
      class function<TObject, void, p_function> // error: invalid parameter type 'void'
      {
      public:
    
          function(TObject& object)
            : p_object(&object)
          {
          }
    
          void operator ()(void)
          {
            // Call the object's member function.
            (p_object->*p_function)();
          }
    
        private:
    
          TObject* p_object;
        };
    "It doesn't matter how beautiful your theory is, it doesn't matter how smart you are. If it doesn't agree with experiment, it's wrong."
    Richard P. Feynman

  2. #2
    Join Date
    Jun 2009
    Location
    France
    Posts
    2,513

    Re: Template specialisation error

    Quote Originally Posted by JohnW@Wessex View Post
    Does anyone know if there's a way to make this specialisation work?
    I have a feeling that it is not possible to do what I want. Can anyone prove me wrong?

    The previous incarnation of the original code passes the member function pointer as a parameter in the constructor.
    With this code I am attempting to get the address at compile time.

    Code:
      template <typename TObject, typename TParameter, void(TObject::*p_function)(TParameter)>
      class function
      {
      public:
    
        function(TObject& object)
          : p_object(&object)
        {
        }
    
        void operator ()(TParameter data)
        {
          // Call the object's member function with the data.
          (p_object->*p_function)(data);
        }
    
      private:
    
        TObject* p_object;
      };
    
      // Specialisation
      template <typename TObject, void(TObject::*p_function)(void)>
      class function<TObject, void, p_function> // error: invalid parameter type 'void'
      {
      public:
    
          function(TObject& object)
            : p_object(&object)
          {
          }
    
          void operator ()(void)
          {
            // Call the object's member function.
            (p_object->*p_function)();
          }
    
        private:
    
          TObject* p_object;
        };
    The issue is that you can only use "(void)" at syntax level, for C compatibility. But inside templates, you are way past that phase, and the compiler will not accept passing the *actual* void type.

    One other thing I tried to do was to declare a base template, with an extra type "PType" that is the function pointer type, and then try to specialize on the type of the function pointer. The odd thing is that the compiler never saw the specialization, but when I removed the base template, it did see it...?

    Anyways, if you are OK with nesting templates, then this is something that varargs could solve in a more generic way:
    Code:
    #include <iostream>
    
    using namespace std;
    
    struct Object {
        void foo(int);
        void bar();
        void baz(long, long);
        void baz(long, long, long);
    };
    
      template<typename TObject, typename... TParameter>
      class function
      {
        public:
          
          template<void(TObject::*p_function)(TParameter...)>
          class instance {
            public:
        
            instance(TObject& object)
              : p_object(&object)
            {
            }
        
            void operator ()(TParameter... data)
            {
              // Call the object's member function with the data.
              (p_object->*p_function)(data...);
            }
        
          private:
        
            TObject* p_object;
          };
        };
    
    
    
    int main()
    {
        Object object;\
        function<Object, int>::instance<&Object::foo> for_foo(object);
        function<Object>::instance<&Object::bar> for_bar(object);
        function<Object, long, long>::instance<&Object::baz> for_baz1(object);
        function<Object, long, long, long>::instance<&Object::baz> for_baz2(object);
        
       cout << "Hello World" << endl; 
    }
    The main issue is that the parameter types must be declared before the function type, but by them you are not allowed to have any more parameters. The workaround here is a nested class to add more parameters. The end call is kind of clunky, but could be solved with "auto"+helper function, or maybe template aliases.

    Note that this approach handles any amount of arguments, and overloads.
    Is your question related to IO?
    Read this C++ FAQ article at parashift by Marshall Cline. In particular points 1-6.
    It will explain how to correctly deal with IO, how to validate input, and why you shouldn't count on "while(!in.eof())". And it always makes for excellent reading.

  3. #3
    Join Date
    Jun 2009
    Location
    France
    Posts
    2,513

    Re: Template specialisation error

    Alternatively, you could use something such as function_traits to extract the arguments of your function pointer directly.
    Is your question related to IO?
    Read this C++ FAQ article at parashift by Marshall Cline. In particular points 1-6.
    It will explain how to correctly deal with IO, how to validate input, and why you shouldn't count on "while(!in.eof())". And it always makes for excellent reading.

  4. #4
    Join Date
    Jun 2009
    Location
    France
    Posts
    2,513

    Re: Template specialisation error

    So, have you had much luck on your end finding a better solution?

    I'm pretty sure there could be ways for you to define the template in the form:
    function<std::function<args>, actual_function> your_instance;

    But have been unable to do this.

    Alternativelly, I'd still be interested in knowing if you succeeded in providing "overloads" so that this actually works:
    function<TObject, actual_function> your_instance0;
    function<TObject, ARG_TYPE_ONE, actual_function> your_instance1;
    function<TObject, ARG_TYPE_ONE, ARG_TYPE_TWO, actual_function> your_instance1;

    Because the last argument is not a type, this should be possible. I'd also be very interested in getting something like that to work.
    Is your question related to IO?
    Read this C++ FAQ article at parashift by Marshall Cline. In particular points 1-6.
    It will explain how to correctly deal with IO, how to validate input, and why you shouldn't count on "while(!in.eof())". And it always makes for excellent reading.

  5. #5
    Join Date
    Oct 2008
    Posts
    1,456

    Re: Template specialisation error

    Quote Originally Posted by monarch_dodra View Post
    I'm pretty sure there could be ways for you to define the template in the form:
    function<std::function<args>, actual_function> your_instance;
    something like

    Code:
    template < typename... T >
    struct args {};
    
    template < typename T, typename Args >
    struct function_ptr
    {
    };
    
    template < typename T, typename... Args >
    struct function_ptr<T,args<Args...>>
    {
        typedef void (T::*type)(Args...);
    };
    
    template < typename T, typename Args, typename function_ptr<T,Args>::type fptr >
    struct function
    {
        // ...
    };
    
    // function< foo, args<int>, &foo::bar >
    ?

  6. #6
    Join Date
    Oct 2008
    Posts
    1,456

    Re: Template specialisation error

    or, more concisely

    Code:
    template < typename Signature >
    struct function_ptr
    {
    };
    
    template < typename T, typename... Args >
    struct function_ptr<T(Args...)>
    {
        typedef void (T::*type)(Args...);
    };
    
    template < typename Signature, typename function_ptr<Signature>::type fptr >
    struct function
    {
        // ...
    };
    
    // function< foo(int), &foo::bar >

  7. #7
    Join Date
    Jun 2009
    Location
    France
    Posts
    2,513

    Re: Template specialisation error

    Quote Originally Posted by superbonzo View Post
    or, more concisely

    Code:
    template < typename Signature >
    struct function_ptr
    {
    };
    
    template < typename T, typename... Args >
    struct function_ptr<T(Args...)>
    {
        typedef void (T::*type)(Args...);
    };
    
    template < typename Signature, typename function_ptr<Signature>::type fptr >
    struct function
    {
        // ...
    };
    
    // function< foo(int), &foo::bar >
    That works, but the issue (I had) remains that we (I) can't extract "Args" back out from function_ptr (or signature).

    I've been able to extract the "T", but how do you implement operator()?
    Code:
        void operator ()(Args... args) // HERE
        {
          (p_object->*fptr)(args);
        }
    AFAIK, you can't typedef a vararg, so you can't extract the args back out of Signature, even with traits...?
    Is your question related to IO?
    Read this C++ FAQ article at parashift by Marshall Cline. In particular points 1-6.
    It will explain how to correctly deal with IO, how to validate input, and why you shouldn't count on "while(!in.eof())". And it always makes for excellent reading.

  8. #8
    Join Date
    Oct 2008
    Posts
    1,456

    Re: Template specialisation error

    Quote Originally Posted by monarch_dodra View Post
    That works, but the issue (I had) remains that we (I) can't extract "Args" back out from function_ptr (or signature).
    you can do it ( unless I'm missing something, just inherit operator() from a suitably specialized implementation base class ) but should you ? I think a perfectly forwarding operator() would be easier to write and more correct for the OP use case ...

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured