简体   繁体   中英

How should I overload a templated struct?

I wish to write a templated struct such that can accept 2 or 3 typenames. However, the program produces an error, template<class F1, class F2, class F3>...' cannot be overloaded . How can this be corrected?

template< typename F1, typename F2, typename F3>    // this shouldn't be right because the compiler expects three typenames, and the program can provide two 
struct Force{
    F1 force1;
    F2 force2;
    F3 force3;

    Force(F1 f1, F2 f2) : force1(f1), force2(f2) {    // construct out of two forces
    }

    Force(F1 f1, F2 f2, F3 f3) : force1(f1), force2(f2), force3(f3) {   // construct out of three forces
    }

    Point operator()(double t) {
        return force1(t) + force2(t);
    }

    Point operator()(double t) {    // this overloading should not be right because it has the same signature as above
        return force1(t) + force2(t) + force3(t);
    }   
};

// this is used by the main program
      template< typename F1, typename F2>
      Force<F1, F2> make_physics(F1 first, F2 second){ 
        return Force<F1, F2>(first, second);
      }

// this is used by the main program
      template< typename F1, typename F2, typename F3>
      Force<F1, F2, F3> make_physics(F1 first, F2 second, F3 third){ 
        return Force<F1, F2, F3>(first, second, third);
      }  

To simplify the presentation, I have replaced the type Point by double . The code below should be enough to make my point:

// This will be the default F3 argument. It's basically a "zero force".
struct zero {
    double operator()(double) { return 0.0; } 
};

// You only need one struct Force
template< typename F1, typename F2, typename F3 = zero>
struct Force {

   F1 force1;
   F2 force2;
   F3 force3;

   Force(F1 f1, F2 f2, F3 f3 = zero()) : force1(f1), force2(f2), force3(f3) {   // construct out of three forces
   }

   double operator()(double t) {
       return force1(t) + force2(t) + force3(t);
   }   
};

// You might provide two make_physics overload for 2D and 3D problems (that's what you want, right?)
template< typename F1, typename F2>
Force<F1, F2> make_physics(F1 first, F2 second){ 
    return Force<F1, F2>(first, second);
}

template< typename F1, typename F2, typename F3>
Force<F1, F2, F3> make_physics(F1 first, F2 second, F3 third){ 
    return Force<F1, F2, F3>(first, second, third);
}

If your compiler has a good C++11 coverage, then you can replace the overloads of make_physics with a variadic template function. In addition, since this is a factory function that just forwards its arguments to Force 's constructor, you should use universal references and perfect forwarding. The code should be like:

template< typename F1, typename F2, typename... F3>
Force<F1, F2, F3...> make_physics(F1&& first, F2&& second, F3&&... third){ 
    return Force<F1, F2, F3...>(std::forward<F1>(first), std::forward<F2>(second), std::forward<F3>(third)...);
}

You can read about http://en.wikipedia.org/wiki/Variadic_template (variadic templates)..

Or you can give the templates default parameters like that:

template< typename F1, typename F2 = void, typename F3 = void>  

both are not yet implemented in visual studio 2012 however... not sure what you use

Or (and you might not like that) Duplicate your class(different names..) and template each above 1, 2 and 3 parameters...

You can use variadic templates along with a tuple :

template<typename... F>
struct Force
{
    std::tuple<F...> f;
};

You can also provide different specialization (this method was used in C++03):

template<typename F1, typename F2 = void, typename F3 = void>
struct Force
{
    F1 a;
    F2 b;
    F3 c;
};

template<typename F1, typename F2>
struct Force<F1,F2,void>
{
    F1 a;
    F2 b;
};

// and so on...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM