Avoid accumulation of iterator types in template arguments












2















Following principle: when I want to return a collection from a function I will pass an output iterator and let the caller decide where the output should go.



Consider the class which has n methods and each one returns some collection. This mean that I need to construct class with n template parameters (output iterators). The number of template parameters will start to grow, and I don't know how to handle this problem.



Specific example:



template<class TNode, class TEdge> class AGraph;
template<class TNode, class TEdge, class OutputOfFunc1, class OutputOfFunc2>
class APathCalculation
{
using TGraph = AGraph<TNode, TEdge>;
public:
virtual void ReturnShortestPath(size_t source, size_t dest, TGraph& graph, OutputOfFunc1 outPath) = 0;//func1
virtual void ReturnAllShortestDistances(size_t source, TGraph& graph, OutputOfFunc2 outDistances) = 0;//func2
};


And, I will derive different classes (e.g. Dijkstra, Bellman-Ford) from APathCalculation. But the problem is that I introduce template arguments



...class OutputOfFunc1, class OutputOfFunc2>


which I fell that they should not be in the class definition since they are specific to particular function.



Currently I declare the class like this



// Example of declaration
APathCalculation<
int, // type of node
double, // type of edge
back_insert_iterator<list<size_t>>, // return type of shortest path between two nodes
back_insert_iterator<vector<double>> // return type of shortest distances from source node
> &pathCalculator;









share|improve this question























  • "I fell that they should not be in the class definition since they are specific to particular function" you know that you can make the individual methods templated?

    – user463035818
    Nov 22 '18 at 13:54








  • 1





    @user463035818 I cannot make it template virtual. Implementation of path calculation is in derived class.

    – Dejan
    Nov 22 '18 at 13:55






  • 1





    i am not sure if I understand your code, hence let me just ask another question. You know that Two classes, one derived from APathCalculation<int,double,some_iterator_type_A> and another deriving from APathCalculation<int,double,some_iterator_type_B>, are completely unrelated (ie they do not share a common base class) ?

    – user463035818
    Nov 22 '18 at 13:59











  • @user463035818 Let's say that I want to make different implementaion of shortest path (in derived classes). If base class function return e.g. vector<TEdge> then I do not have this problem. But I want more general solution, I do not want to put vector in abstract class declaration (why function wouldn't be able to return list for example).

    – Dejan
    Nov 22 '18 at 14:07






  • 1





    @Dejan His question was not about that. The question is "why do you implement the algorithms in derived classes of that base class? Why use polymorphy?". If the answer to that is "because I want to store different instances of that algorithm through the base class interface", then his point is "you can't do that if the base classes are different template instantiations".

    – Max Langhof
    Nov 22 '18 at 14:10
















2















Following principle: when I want to return a collection from a function I will pass an output iterator and let the caller decide where the output should go.



Consider the class which has n methods and each one returns some collection. This mean that I need to construct class with n template parameters (output iterators). The number of template parameters will start to grow, and I don't know how to handle this problem.



Specific example:



template<class TNode, class TEdge> class AGraph;
template<class TNode, class TEdge, class OutputOfFunc1, class OutputOfFunc2>
class APathCalculation
{
using TGraph = AGraph<TNode, TEdge>;
public:
virtual void ReturnShortestPath(size_t source, size_t dest, TGraph& graph, OutputOfFunc1 outPath) = 0;//func1
virtual void ReturnAllShortestDistances(size_t source, TGraph& graph, OutputOfFunc2 outDistances) = 0;//func2
};


And, I will derive different classes (e.g. Dijkstra, Bellman-Ford) from APathCalculation. But the problem is that I introduce template arguments



...class OutputOfFunc1, class OutputOfFunc2>


which I fell that they should not be in the class definition since they are specific to particular function.



Currently I declare the class like this



// Example of declaration
APathCalculation<
int, // type of node
double, // type of edge
back_insert_iterator<list<size_t>>, // return type of shortest path between two nodes
back_insert_iterator<vector<double>> // return type of shortest distances from source node
> &pathCalculator;









share|improve this question























  • "I fell that they should not be in the class definition since they are specific to particular function" you know that you can make the individual methods templated?

    – user463035818
    Nov 22 '18 at 13:54








  • 1





    @user463035818 I cannot make it template virtual. Implementation of path calculation is in derived class.

    – Dejan
    Nov 22 '18 at 13:55






  • 1





    i am not sure if I understand your code, hence let me just ask another question. You know that Two classes, one derived from APathCalculation<int,double,some_iterator_type_A> and another deriving from APathCalculation<int,double,some_iterator_type_B>, are completely unrelated (ie they do not share a common base class) ?

    – user463035818
    Nov 22 '18 at 13:59











  • @user463035818 Let's say that I want to make different implementaion of shortest path (in derived classes). If base class function return e.g. vector<TEdge> then I do not have this problem. But I want more general solution, I do not want to put vector in abstract class declaration (why function wouldn't be able to return list for example).

    – Dejan
    Nov 22 '18 at 14:07






  • 1





    @Dejan His question was not about that. The question is "why do you implement the algorithms in derived classes of that base class? Why use polymorphy?". If the answer to that is "because I want to store different instances of that algorithm through the base class interface", then his point is "you can't do that if the base classes are different template instantiations".

    – Max Langhof
    Nov 22 '18 at 14:10














2












2








2


1






Following principle: when I want to return a collection from a function I will pass an output iterator and let the caller decide where the output should go.



Consider the class which has n methods and each one returns some collection. This mean that I need to construct class with n template parameters (output iterators). The number of template parameters will start to grow, and I don't know how to handle this problem.



Specific example:



template<class TNode, class TEdge> class AGraph;
template<class TNode, class TEdge, class OutputOfFunc1, class OutputOfFunc2>
class APathCalculation
{
using TGraph = AGraph<TNode, TEdge>;
public:
virtual void ReturnShortestPath(size_t source, size_t dest, TGraph& graph, OutputOfFunc1 outPath) = 0;//func1
virtual void ReturnAllShortestDistances(size_t source, TGraph& graph, OutputOfFunc2 outDistances) = 0;//func2
};


And, I will derive different classes (e.g. Dijkstra, Bellman-Ford) from APathCalculation. But the problem is that I introduce template arguments



...class OutputOfFunc1, class OutputOfFunc2>


which I fell that they should not be in the class definition since they are specific to particular function.



Currently I declare the class like this



// Example of declaration
APathCalculation<
int, // type of node
double, // type of edge
back_insert_iterator<list<size_t>>, // return type of shortest path between two nodes
back_insert_iterator<vector<double>> // return type of shortest distances from source node
> &pathCalculator;









share|improve this question














Following principle: when I want to return a collection from a function I will pass an output iterator and let the caller decide where the output should go.



Consider the class which has n methods and each one returns some collection. This mean that I need to construct class with n template parameters (output iterators). The number of template parameters will start to grow, and I don't know how to handle this problem.



Specific example:



template<class TNode, class TEdge> class AGraph;
template<class TNode, class TEdge, class OutputOfFunc1, class OutputOfFunc2>
class APathCalculation
{
using TGraph = AGraph<TNode, TEdge>;
public:
virtual void ReturnShortestPath(size_t source, size_t dest, TGraph& graph, OutputOfFunc1 outPath) = 0;//func1
virtual void ReturnAllShortestDistances(size_t source, TGraph& graph, OutputOfFunc2 outDistances) = 0;//func2
};


And, I will derive different classes (e.g. Dijkstra, Bellman-Ford) from APathCalculation. But the problem is that I introduce template arguments



...class OutputOfFunc1, class OutputOfFunc2>


which I fell that they should not be in the class definition since they are specific to particular function.



Currently I declare the class like this



// Example of declaration
APathCalculation<
int, // type of node
double, // type of edge
back_insert_iterator<list<size_t>>, // return type of shortest path between two nodes
back_insert_iterator<vector<double>> // return type of shortest distances from source node
> &pathCalculator;






c++ templates iterator






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 22 '18 at 13:52









DejanDejan

333314




333314













  • "I fell that they should not be in the class definition since they are specific to particular function" you know that you can make the individual methods templated?

    – user463035818
    Nov 22 '18 at 13:54








  • 1





    @user463035818 I cannot make it template virtual. Implementation of path calculation is in derived class.

    – Dejan
    Nov 22 '18 at 13:55






  • 1





    i am not sure if I understand your code, hence let me just ask another question. You know that Two classes, one derived from APathCalculation<int,double,some_iterator_type_A> and another deriving from APathCalculation<int,double,some_iterator_type_B>, are completely unrelated (ie they do not share a common base class) ?

    – user463035818
    Nov 22 '18 at 13:59











  • @user463035818 Let's say that I want to make different implementaion of shortest path (in derived classes). If base class function return e.g. vector<TEdge> then I do not have this problem. But I want more general solution, I do not want to put vector in abstract class declaration (why function wouldn't be able to return list for example).

    – Dejan
    Nov 22 '18 at 14:07






  • 1





    @Dejan His question was not about that. The question is "why do you implement the algorithms in derived classes of that base class? Why use polymorphy?". If the answer to that is "because I want to store different instances of that algorithm through the base class interface", then his point is "you can't do that if the base classes are different template instantiations".

    – Max Langhof
    Nov 22 '18 at 14:10



















  • "I fell that they should not be in the class definition since they are specific to particular function" you know that you can make the individual methods templated?

    – user463035818
    Nov 22 '18 at 13:54








  • 1





    @user463035818 I cannot make it template virtual. Implementation of path calculation is in derived class.

    – Dejan
    Nov 22 '18 at 13:55






  • 1





    i am not sure if I understand your code, hence let me just ask another question. You know that Two classes, one derived from APathCalculation<int,double,some_iterator_type_A> and another deriving from APathCalculation<int,double,some_iterator_type_B>, are completely unrelated (ie they do not share a common base class) ?

    – user463035818
    Nov 22 '18 at 13:59











  • @user463035818 Let's say that I want to make different implementaion of shortest path (in derived classes). If base class function return e.g. vector<TEdge> then I do not have this problem. But I want more general solution, I do not want to put vector in abstract class declaration (why function wouldn't be able to return list for example).

    – Dejan
    Nov 22 '18 at 14:07






  • 1





    @Dejan His question was not about that. The question is "why do you implement the algorithms in derived classes of that base class? Why use polymorphy?". If the answer to that is "because I want to store different instances of that algorithm through the base class interface", then his point is "you can't do that if the base classes are different template instantiations".

    – Max Langhof
    Nov 22 '18 at 14:10

















"I fell that they should not be in the class definition since they are specific to particular function" you know that you can make the individual methods templated?

– user463035818
Nov 22 '18 at 13:54







"I fell that they should not be in the class definition since they are specific to particular function" you know that you can make the individual methods templated?

– user463035818
Nov 22 '18 at 13:54






1




1





@user463035818 I cannot make it template virtual. Implementation of path calculation is in derived class.

– Dejan
Nov 22 '18 at 13:55





@user463035818 I cannot make it template virtual. Implementation of path calculation is in derived class.

– Dejan
Nov 22 '18 at 13:55




1




1





i am not sure if I understand your code, hence let me just ask another question. You know that Two classes, one derived from APathCalculation<int,double,some_iterator_type_A> and another deriving from APathCalculation<int,double,some_iterator_type_B>, are completely unrelated (ie they do not share a common base class) ?

– user463035818
Nov 22 '18 at 13:59





i am not sure if I understand your code, hence let me just ask another question. You know that Two classes, one derived from APathCalculation<int,double,some_iterator_type_A> and another deriving from APathCalculation<int,double,some_iterator_type_B>, are completely unrelated (ie they do not share a common base class) ?

– user463035818
Nov 22 '18 at 13:59













@user463035818 Let's say that I want to make different implementaion of shortest path (in derived classes). If base class function return e.g. vector<TEdge> then I do not have this problem. But I want more general solution, I do not want to put vector in abstract class declaration (why function wouldn't be able to return list for example).

– Dejan
Nov 22 '18 at 14:07





@user463035818 Let's say that I want to make different implementaion of shortest path (in derived classes). If base class function return e.g. vector<TEdge> then I do not have this problem. But I want more general solution, I do not want to put vector in abstract class declaration (why function wouldn't be able to return list for example).

– Dejan
Nov 22 '18 at 14:07




1




1





@Dejan His question was not about that. The question is "why do you implement the algorithms in derived classes of that base class? Why use polymorphy?". If the answer to that is "because I want to store different instances of that algorithm through the base class interface", then his point is "you can't do that if the base classes are different template instantiations".

– Max Langhof
Nov 22 '18 at 14:10





@Dejan His question was not about that. The question is "why do you implement the algorithms in derived classes of that base class? Why use polymorphy?". If the answer to that is "because I want to store different instances of that algorithm through the base class interface", then his point is "you can't do that if the base classes are different template instantiations".

– Max Langhof
Nov 22 '18 at 14:10












4 Answers
4






active

oldest

votes


















1














Here are three alternatives to consider:



Option 1: Just pick a type and return it



If you're worried about performance, this likely isn't nearly as bad as you think.



virtual std::vector<TEdge> FindShortestPath(size_t source, size_t dest, TGraph& graph) = 0;


Option 2: Accept a callback



The idea is that the caller will supply a lambda that stores the output in whatever way makes sense.



virtual void TraverseShortestPath(
size_t source,
size_t dest,
TGraph& graph,
std::function<void(TEdge*)> callback) = 0;


Option 3: Use a function template



It's a little mysterious to me why you want to use polymorphism for this. You could write function templates for different shortest path algorithms (similar to the algorithms style in the STL):



template <class TGraph, class OutIt>
void FindShortestPath(size_t source, size_t dest, TGraph& graph, OutIt output)
{
// details...
}


There are of course lots of variations you could do on these approaches. I would also caution against the use of output iterators like this. The caller could pass something safe like a back_inserter but could also pass in something dangerous like a raw pointer, which could easily lead to a buffer overrun.






share|improve this answer


























  • In option 3: I am loosing polymorphism. Option 1 is not general since I am specifying the return type. But option 2 sounds interesting, something that it doesn't came to my mind. Maybe, I should think to write library in that way.

    – Dejan
    Nov 22 '18 at 15:01






  • 1





    Option (3) looses runtime polymorphism, but why do you need it? Do you really expect users of your library to choose different shortest path algorithms at runtime?

    – Peter Ruderman
    Nov 22 '18 at 15:03





















2















"Consider the class which has n methods and each one returns some
collection. This mean that I need to construct class with n template
parameters (output iterators).




No, you don't. You coudd in fact create a class with 0 template parameters. However, each method itself has one template parameter. In your case, you can reduce it to just 2 template parameters for the class:



template<class TNode, class TEdge>
class APathCalculation
{
using TGraph = AGraph<TNode, TEdge>;
public:
template<class OutputOfFunc1>
void ReturnShortestPath(size_t source, size_t dest, TGraph& graph, OutputOfFunc1 outPath);

template<class OutputOfFunc2>
void ReturnAllShortestDistances(size_t source, TGraph& graph, OutputOfFunc2 outDistances);
};


Please note that I have made one important change here: this is a class in the OO sense. What you had was an abstract class or interface. Abstract classes are a good way to decouple caller and callee, but here you cannot decouple them: the caller and callee must agree on iterator types.






share|improve this answer
























  • You lost virtual, polymorphism and decoupling. If the caller calls only one function, he must agree on output iterator types. That is fine. But that caller function also need to agree on other n-1 iterators which he doesn't use. This part is bad.

    – Dejan
    Nov 22 '18 at 14:29













  • @Dejan: No, they don't. Not in this solution. The caller of APathCalculation<TNode, TEdge>::ReturnShortestPath<OutputOfFunc1> clearly does not need to specify OutputOfFunc2. I indeed removed polymorpism, intentionally.

    – MSalters
    Nov 22 '18 at 14:30













  • Yes in that case. But you lost polymorphism then. Having abstract class for path calculation makes sense to me. Will you design your library without such abstract class?

    – Dejan
    Nov 22 '18 at 14:34






  • 1





    @Dejan: Yes. That is the modern C++ style. All those iterators do not share an abstract base class either.

    – MSalters
    Nov 22 '18 at 14:36






  • 1





    @Dejan its not clear how you intend to use the base class. Note that already "And, I will derive different classes (e.g. Dijkstra, Bellman-Ford) from APathCalculation." is strictly speaking wrong. In your code APathCalculation is not a class, its just a template, as such you cannot derive from it. You first have to instantiate it. Classes deriving from two different instantations of the same template are not polymorphic

    – user463035818
    Nov 22 '18 at 14:37



















0














You may define all your arguments in a single structure and use them all over your structures like this:



template<class TNode, class TEdge> class AGraph;

template< typename TYPE_DEFS >
class APathCalculation
{
using TGraph = AGraph<typename TYPE_DEFS::TNode, typename TYPE_DEFS::TEdge>;
public:
virtual void ReturnShortestPath(size_t source, size_t dest, TGraph& graph, typename TYPE_DEFS::OutputOfFunc1 outPath) = 0;//func1
virtual void ReturnAllShortestDistances(size_t source, TGraph& graph, typename TYPE_DEFS::OutputOfFunc2 outDistances) = 0;//func2
};


template< typename TYPE_DEFS >
class Dijkstra: public APathCalculation<TYPE_DEFS>
{
using TGraph = AGraph<typename TYPE_DEFS::TNode, typename TYPE_DEFS::TEdge>;
public:
virtual void ReturnShortestPath(size_t source, size_t dest, TGraph& graph, typename TYPE_DEFS::OutputOfFunc1 outPath) override {}
virtual void ReturnAllShortestDistances(size_t source, TGraph& graph, typename TYPE_DEFS::OutputOfFunc2 outDistances) override {}
};

struct TypeDefs
{
using TNode = int;
using TEdge = double;

using OutputOfFunc1 = std::back_insert_iterator<std::list<size_t>>;
using OutputOfFunc2 = std::back_insert_iterator<std::vector<double>>;
};

int main()
{
Dijkstra<TypeDefs> d;
}


All that will not change anything of your binary. It only makes it a bit more convenient. But maybe I have misunderstood your question?






share|improve this answer































    0














    A "shallow" answer:



    In order to avoid N template parameters in one class, you need to split it into N classes with 1 template parameter each.



    A "deep" answer:



    You cannot easily combine dynamic (runtime) polymorphism of virtual functions with static (compile-time, template based) polymorphism of its argument types. If users of the APathCalculation interface want to provide their own iterator class, they will need to instantiate all the potentially useful actual implementations of this interface for their iterator class, which makes dynamic polymorphism for APathCalculation a redundant idea.



    If you really need dynamic polymorphism, you need a dynamically polymorphous iterator class.



    You can actually have both (statically polymorphous template specializations for common algorithms and/or common iterators, backed by a "default" case that is a wrapper to dynamically polymorphous implementations), but that's probably too complicated for your task. Besides, you will still need a way to bind your "default" wrapper to the actual algorithm you want the APathCalculation client to call.



    I personally would start with a purely template-based solution, but I could understand someone starting with a purely virtual function based solution.






    share|improve this answer
























    • If you really need dynamic polymorphism, you need a dynamically polymorphous iterator class. I don't understand this. Can you explain what you mean with this? How the signature in abstract class will look like in that case?

      – Dejan
      Nov 22 '18 at 16:27











    • It could be a functor (either std::function or a class with a virtual function interface), or, if you want to use in place of "normal" output iterators, it could be a wrapper class that satisfies OutputIterator requirements and redirects the required operator calls to the underlying polymorphous class (which it may hold by reference). You can look at the std::back_insert_iterator implementation in order to see which methods you need to implement.

      – Kit.
      Nov 22 '18 at 17:04













    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53432489%2favoid-accumulation-of-iterator-types-in-template-arguments%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    4 Answers
    4






    active

    oldest

    votes








    4 Answers
    4






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    1














    Here are three alternatives to consider:



    Option 1: Just pick a type and return it



    If you're worried about performance, this likely isn't nearly as bad as you think.



    virtual std::vector<TEdge> FindShortestPath(size_t source, size_t dest, TGraph& graph) = 0;


    Option 2: Accept a callback



    The idea is that the caller will supply a lambda that stores the output in whatever way makes sense.



    virtual void TraverseShortestPath(
    size_t source,
    size_t dest,
    TGraph& graph,
    std::function<void(TEdge*)> callback) = 0;


    Option 3: Use a function template



    It's a little mysterious to me why you want to use polymorphism for this. You could write function templates for different shortest path algorithms (similar to the algorithms style in the STL):



    template <class TGraph, class OutIt>
    void FindShortestPath(size_t source, size_t dest, TGraph& graph, OutIt output)
    {
    // details...
    }


    There are of course lots of variations you could do on these approaches. I would also caution against the use of output iterators like this. The caller could pass something safe like a back_inserter but could also pass in something dangerous like a raw pointer, which could easily lead to a buffer overrun.






    share|improve this answer


























    • In option 3: I am loosing polymorphism. Option 1 is not general since I am specifying the return type. But option 2 sounds interesting, something that it doesn't came to my mind. Maybe, I should think to write library in that way.

      – Dejan
      Nov 22 '18 at 15:01






    • 1





      Option (3) looses runtime polymorphism, but why do you need it? Do you really expect users of your library to choose different shortest path algorithms at runtime?

      – Peter Ruderman
      Nov 22 '18 at 15:03


















    1














    Here are three alternatives to consider:



    Option 1: Just pick a type and return it



    If you're worried about performance, this likely isn't nearly as bad as you think.



    virtual std::vector<TEdge> FindShortestPath(size_t source, size_t dest, TGraph& graph) = 0;


    Option 2: Accept a callback



    The idea is that the caller will supply a lambda that stores the output in whatever way makes sense.



    virtual void TraverseShortestPath(
    size_t source,
    size_t dest,
    TGraph& graph,
    std::function<void(TEdge*)> callback) = 0;


    Option 3: Use a function template



    It's a little mysterious to me why you want to use polymorphism for this. You could write function templates for different shortest path algorithms (similar to the algorithms style in the STL):



    template <class TGraph, class OutIt>
    void FindShortestPath(size_t source, size_t dest, TGraph& graph, OutIt output)
    {
    // details...
    }


    There are of course lots of variations you could do on these approaches. I would also caution against the use of output iterators like this. The caller could pass something safe like a back_inserter but could also pass in something dangerous like a raw pointer, which could easily lead to a buffer overrun.






    share|improve this answer


























    • In option 3: I am loosing polymorphism. Option 1 is not general since I am specifying the return type. But option 2 sounds interesting, something that it doesn't came to my mind. Maybe, I should think to write library in that way.

      – Dejan
      Nov 22 '18 at 15:01






    • 1





      Option (3) looses runtime polymorphism, but why do you need it? Do you really expect users of your library to choose different shortest path algorithms at runtime?

      – Peter Ruderman
      Nov 22 '18 at 15:03
















    1












    1








    1







    Here are three alternatives to consider:



    Option 1: Just pick a type and return it



    If you're worried about performance, this likely isn't nearly as bad as you think.



    virtual std::vector<TEdge> FindShortestPath(size_t source, size_t dest, TGraph& graph) = 0;


    Option 2: Accept a callback



    The idea is that the caller will supply a lambda that stores the output in whatever way makes sense.



    virtual void TraverseShortestPath(
    size_t source,
    size_t dest,
    TGraph& graph,
    std::function<void(TEdge*)> callback) = 0;


    Option 3: Use a function template



    It's a little mysterious to me why you want to use polymorphism for this. You could write function templates for different shortest path algorithms (similar to the algorithms style in the STL):



    template <class TGraph, class OutIt>
    void FindShortestPath(size_t source, size_t dest, TGraph& graph, OutIt output)
    {
    // details...
    }


    There are of course lots of variations you could do on these approaches. I would also caution against the use of output iterators like this. The caller could pass something safe like a back_inserter but could also pass in something dangerous like a raw pointer, which could easily lead to a buffer overrun.






    share|improve this answer















    Here are three alternatives to consider:



    Option 1: Just pick a type and return it



    If you're worried about performance, this likely isn't nearly as bad as you think.



    virtual std::vector<TEdge> FindShortestPath(size_t source, size_t dest, TGraph& graph) = 0;


    Option 2: Accept a callback



    The idea is that the caller will supply a lambda that stores the output in whatever way makes sense.



    virtual void TraverseShortestPath(
    size_t source,
    size_t dest,
    TGraph& graph,
    std::function<void(TEdge*)> callback) = 0;


    Option 3: Use a function template



    It's a little mysterious to me why you want to use polymorphism for this. You could write function templates for different shortest path algorithms (similar to the algorithms style in the STL):



    template <class TGraph, class OutIt>
    void FindShortestPath(size_t source, size_t dest, TGraph& graph, OutIt output)
    {
    // details...
    }


    There are of course lots of variations you could do on these approaches. I would also caution against the use of output iterators like this. The caller could pass something safe like a back_inserter but could also pass in something dangerous like a raw pointer, which could easily lead to a buffer overrun.







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Nov 22 '18 at 14:50

























    answered Nov 22 '18 at 14:40









    Peter RudermanPeter Ruderman

    10.2k2352




    10.2k2352













    • In option 3: I am loosing polymorphism. Option 1 is not general since I am specifying the return type. But option 2 sounds interesting, something that it doesn't came to my mind. Maybe, I should think to write library in that way.

      – Dejan
      Nov 22 '18 at 15:01






    • 1





      Option (3) looses runtime polymorphism, but why do you need it? Do you really expect users of your library to choose different shortest path algorithms at runtime?

      – Peter Ruderman
      Nov 22 '18 at 15:03





















    • In option 3: I am loosing polymorphism. Option 1 is not general since I am specifying the return type. But option 2 sounds interesting, something that it doesn't came to my mind. Maybe, I should think to write library in that way.

      – Dejan
      Nov 22 '18 at 15:01






    • 1





      Option (3) looses runtime polymorphism, but why do you need it? Do you really expect users of your library to choose different shortest path algorithms at runtime?

      – Peter Ruderman
      Nov 22 '18 at 15:03



















    In option 3: I am loosing polymorphism. Option 1 is not general since I am specifying the return type. But option 2 sounds interesting, something that it doesn't came to my mind. Maybe, I should think to write library in that way.

    – Dejan
    Nov 22 '18 at 15:01





    In option 3: I am loosing polymorphism. Option 1 is not general since I am specifying the return type. But option 2 sounds interesting, something that it doesn't came to my mind. Maybe, I should think to write library in that way.

    – Dejan
    Nov 22 '18 at 15:01




    1




    1





    Option (3) looses runtime polymorphism, but why do you need it? Do you really expect users of your library to choose different shortest path algorithms at runtime?

    – Peter Ruderman
    Nov 22 '18 at 15:03







    Option (3) looses runtime polymorphism, but why do you need it? Do you really expect users of your library to choose different shortest path algorithms at runtime?

    – Peter Ruderman
    Nov 22 '18 at 15:03















    2















    "Consider the class which has n methods and each one returns some
    collection. This mean that I need to construct class with n template
    parameters (output iterators).




    No, you don't. You coudd in fact create a class with 0 template parameters. However, each method itself has one template parameter. In your case, you can reduce it to just 2 template parameters for the class:



    template<class TNode, class TEdge>
    class APathCalculation
    {
    using TGraph = AGraph<TNode, TEdge>;
    public:
    template<class OutputOfFunc1>
    void ReturnShortestPath(size_t source, size_t dest, TGraph& graph, OutputOfFunc1 outPath);

    template<class OutputOfFunc2>
    void ReturnAllShortestDistances(size_t source, TGraph& graph, OutputOfFunc2 outDistances);
    };


    Please note that I have made one important change here: this is a class in the OO sense. What you had was an abstract class or interface. Abstract classes are a good way to decouple caller and callee, but here you cannot decouple them: the caller and callee must agree on iterator types.






    share|improve this answer
























    • You lost virtual, polymorphism and decoupling. If the caller calls only one function, he must agree on output iterator types. That is fine. But that caller function also need to agree on other n-1 iterators which he doesn't use. This part is bad.

      – Dejan
      Nov 22 '18 at 14:29













    • @Dejan: No, they don't. Not in this solution. The caller of APathCalculation<TNode, TEdge>::ReturnShortestPath<OutputOfFunc1> clearly does not need to specify OutputOfFunc2. I indeed removed polymorpism, intentionally.

      – MSalters
      Nov 22 '18 at 14:30













    • Yes in that case. But you lost polymorphism then. Having abstract class for path calculation makes sense to me. Will you design your library without such abstract class?

      – Dejan
      Nov 22 '18 at 14:34






    • 1





      @Dejan: Yes. That is the modern C++ style. All those iterators do not share an abstract base class either.

      – MSalters
      Nov 22 '18 at 14:36






    • 1





      @Dejan its not clear how you intend to use the base class. Note that already "And, I will derive different classes (e.g. Dijkstra, Bellman-Ford) from APathCalculation." is strictly speaking wrong. In your code APathCalculation is not a class, its just a template, as such you cannot derive from it. You first have to instantiate it. Classes deriving from two different instantations of the same template are not polymorphic

      – user463035818
      Nov 22 '18 at 14:37
















    2















    "Consider the class which has n methods and each one returns some
    collection. This mean that I need to construct class with n template
    parameters (output iterators).




    No, you don't. You coudd in fact create a class with 0 template parameters. However, each method itself has one template parameter. In your case, you can reduce it to just 2 template parameters for the class:



    template<class TNode, class TEdge>
    class APathCalculation
    {
    using TGraph = AGraph<TNode, TEdge>;
    public:
    template<class OutputOfFunc1>
    void ReturnShortestPath(size_t source, size_t dest, TGraph& graph, OutputOfFunc1 outPath);

    template<class OutputOfFunc2>
    void ReturnAllShortestDistances(size_t source, TGraph& graph, OutputOfFunc2 outDistances);
    };


    Please note that I have made one important change here: this is a class in the OO sense. What you had was an abstract class or interface. Abstract classes are a good way to decouple caller and callee, but here you cannot decouple them: the caller and callee must agree on iterator types.






    share|improve this answer
























    • You lost virtual, polymorphism and decoupling. If the caller calls only one function, he must agree on output iterator types. That is fine. But that caller function also need to agree on other n-1 iterators which he doesn't use. This part is bad.

      – Dejan
      Nov 22 '18 at 14:29













    • @Dejan: No, they don't. Not in this solution. The caller of APathCalculation<TNode, TEdge>::ReturnShortestPath<OutputOfFunc1> clearly does not need to specify OutputOfFunc2. I indeed removed polymorpism, intentionally.

      – MSalters
      Nov 22 '18 at 14:30













    • Yes in that case. But you lost polymorphism then. Having abstract class for path calculation makes sense to me. Will you design your library without such abstract class?

      – Dejan
      Nov 22 '18 at 14:34






    • 1





      @Dejan: Yes. That is the modern C++ style. All those iterators do not share an abstract base class either.

      – MSalters
      Nov 22 '18 at 14:36






    • 1





      @Dejan its not clear how you intend to use the base class. Note that already "And, I will derive different classes (e.g. Dijkstra, Bellman-Ford) from APathCalculation." is strictly speaking wrong. In your code APathCalculation is not a class, its just a template, as such you cannot derive from it. You first have to instantiate it. Classes deriving from two different instantations of the same template are not polymorphic

      – user463035818
      Nov 22 '18 at 14:37














    2












    2








    2








    "Consider the class which has n methods and each one returns some
    collection. This mean that I need to construct class with n template
    parameters (output iterators).




    No, you don't. You coudd in fact create a class with 0 template parameters. However, each method itself has one template parameter. In your case, you can reduce it to just 2 template parameters for the class:



    template<class TNode, class TEdge>
    class APathCalculation
    {
    using TGraph = AGraph<TNode, TEdge>;
    public:
    template<class OutputOfFunc1>
    void ReturnShortestPath(size_t source, size_t dest, TGraph& graph, OutputOfFunc1 outPath);

    template<class OutputOfFunc2>
    void ReturnAllShortestDistances(size_t source, TGraph& graph, OutputOfFunc2 outDistances);
    };


    Please note that I have made one important change here: this is a class in the OO sense. What you had was an abstract class or interface. Abstract classes are a good way to decouple caller and callee, but here you cannot decouple them: the caller and callee must agree on iterator types.






    share|improve this answer














    "Consider the class which has n methods and each one returns some
    collection. This mean that I need to construct class with n template
    parameters (output iterators).




    No, you don't. You coudd in fact create a class with 0 template parameters. However, each method itself has one template parameter. In your case, you can reduce it to just 2 template parameters for the class:



    template<class TNode, class TEdge>
    class APathCalculation
    {
    using TGraph = AGraph<TNode, TEdge>;
    public:
    template<class OutputOfFunc1>
    void ReturnShortestPath(size_t source, size_t dest, TGraph& graph, OutputOfFunc1 outPath);

    template<class OutputOfFunc2>
    void ReturnAllShortestDistances(size_t source, TGraph& graph, OutputOfFunc2 outDistances);
    };


    Please note that I have made one important change here: this is a class in the OO sense. What you had was an abstract class or interface. Abstract classes are a good way to decouple caller and callee, but here you cannot decouple them: the caller and callee must agree on iterator types.







    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered Nov 22 '18 at 14:23









    MSaltersMSalters

    134k8117268




    134k8117268













    • You lost virtual, polymorphism and decoupling. If the caller calls only one function, he must agree on output iterator types. That is fine. But that caller function also need to agree on other n-1 iterators which he doesn't use. This part is bad.

      – Dejan
      Nov 22 '18 at 14:29













    • @Dejan: No, they don't. Not in this solution. The caller of APathCalculation<TNode, TEdge>::ReturnShortestPath<OutputOfFunc1> clearly does not need to specify OutputOfFunc2. I indeed removed polymorpism, intentionally.

      – MSalters
      Nov 22 '18 at 14:30













    • Yes in that case. But you lost polymorphism then. Having abstract class for path calculation makes sense to me. Will you design your library without such abstract class?

      – Dejan
      Nov 22 '18 at 14:34






    • 1





      @Dejan: Yes. That is the modern C++ style. All those iterators do not share an abstract base class either.

      – MSalters
      Nov 22 '18 at 14:36






    • 1





      @Dejan its not clear how you intend to use the base class. Note that already "And, I will derive different classes (e.g. Dijkstra, Bellman-Ford) from APathCalculation." is strictly speaking wrong. In your code APathCalculation is not a class, its just a template, as such you cannot derive from it. You first have to instantiate it. Classes deriving from two different instantations of the same template are not polymorphic

      – user463035818
      Nov 22 '18 at 14:37



















    • You lost virtual, polymorphism and decoupling. If the caller calls only one function, he must agree on output iterator types. That is fine. But that caller function also need to agree on other n-1 iterators which he doesn't use. This part is bad.

      – Dejan
      Nov 22 '18 at 14:29













    • @Dejan: No, they don't. Not in this solution. The caller of APathCalculation<TNode, TEdge>::ReturnShortestPath<OutputOfFunc1> clearly does not need to specify OutputOfFunc2. I indeed removed polymorpism, intentionally.

      – MSalters
      Nov 22 '18 at 14:30













    • Yes in that case. But you lost polymorphism then. Having abstract class for path calculation makes sense to me. Will you design your library without such abstract class?

      – Dejan
      Nov 22 '18 at 14:34






    • 1





      @Dejan: Yes. That is the modern C++ style. All those iterators do not share an abstract base class either.

      – MSalters
      Nov 22 '18 at 14:36






    • 1





      @Dejan its not clear how you intend to use the base class. Note that already "And, I will derive different classes (e.g. Dijkstra, Bellman-Ford) from APathCalculation." is strictly speaking wrong. In your code APathCalculation is not a class, its just a template, as such you cannot derive from it. You first have to instantiate it. Classes deriving from two different instantations of the same template are not polymorphic

      – user463035818
      Nov 22 '18 at 14:37

















    You lost virtual, polymorphism and decoupling. If the caller calls only one function, he must agree on output iterator types. That is fine. But that caller function also need to agree on other n-1 iterators which he doesn't use. This part is bad.

    – Dejan
    Nov 22 '18 at 14:29







    You lost virtual, polymorphism and decoupling. If the caller calls only one function, he must agree on output iterator types. That is fine. But that caller function also need to agree on other n-1 iterators which he doesn't use. This part is bad.

    – Dejan
    Nov 22 '18 at 14:29















    @Dejan: No, they don't. Not in this solution. The caller of APathCalculation<TNode, TEdge>::ReturnShortestPath<OutputOfFunc1> clearly does not need to specify OutputOfFunc2. I indeed removed polymorpism, intentionally.

    – MSalters
    Nov 22 '18 at 14:30







    @Dejan: No, they don't. Not in this solution. The caller of APathCalculation<TNode, TEdge>::ReturnShortestPath<OutputOfFunc1> clearly does not need to specify OutputOfFunc2. I indeed removed polymorpism, intentionally.

    – MSalters
    Nov 22 '18 at 14:30















    Yes in that case. But you lost polymorphism then. Having abstract class for path calculation makes sense to me. Will you design your library without such abstract class?

    – Dejan
    Nov 22 '18 at 14:34





    Yes in that case. But you lost polymorphism then. Having abstract class for path calculation makes sense to me. Will you design your library without such abstract class?

    – Dejan
    Nov 22 '18 at 14:34




    1




    1





    @Dejan: Yes. That is the modern C++ style. All those iterators do not share an abstract base class either.

    – MSalters
    Nov 22 '18 at 14:36





    @Dejan: Yes. That is the modern C++ style. All those iterators do not share an abstract base class either.

    – MSalters
    Nov 22 '18 at 14:36




    1




    1





    @Dejan its not clear how you intend to use the base class. Note that already "And, I will derive different classes (e.g. Dijkstra, Bellman-Ford) from APathCalculation." is strictly speaking wrong. In your code APathCalculation is not a class, its just a template, as such you cannot derive from it. You first have to instantiate it. Classes deriving from two different instantations of the same template are not polymorphic

    – user463035818
    Nov 22 '18 at 14:37





    @Dejan its not clear how you intend to use the base class. Note that already "And, I will derive different classes (e.g. Dijkstra, Bellman-Ford) from APathCalculation." is strictly speaking wrong. In your code APathCalculation is not a class, its just a template, as such you cannot derive from it. You first have to instantiate it. Classes deriving from two different instantations of the same template are not polymorphic

    – user463035818
    Nov 22 '18 at 14:37











    0














    You may define all your arguments in a single structure and use them all over your structures like this:



    template<class TNode, class TEdge> class AGraph;

    template< typename TYPE_DEFS >
    class APathCalculation
    {
    using TGraph = AGraph<typename TYPE_DEFS::TNode, typename TYPE_DEFS::TEdge>;
    public:
    virtual void ReturnShortestPath(size_t source, size_t dest, TGraph& graph, typename TYPE_DEFS::OutputOfFunc1 outPath) = 0;//func1
    virtual void ReturnAllShortestDistances(size_t source, TGraph& graph, typename TYPE_DEFS::OutputOfFunc2 outDistances) = 0;//func2
    };


    template< typename TYPE_DEFS >
    class Dijkstra: public APathCalculation<TYPE_DEFS>
    {
    using TGraph = AGraph<typename TYPE_DEFS::TNode, typename TYPE_DEFS::TEdge>;
    public:
    virtual void ReturnShortestPath(size_t source, size_t dest, TGraph& graph, typename TYPE_DEFS::OutputOfFunc1 outPath) override {}
    virtual void ReturnAllShortestDistances(size_t source, TGraph& graph, typename TYPE_DEFS::OutputOfFunc2 outDistances) override {}
    };

    struct TypeDefs
    {
    using TNode = int;
    using TEdge = double;

    using OutputOfFunc1 = std::back_insert_iterator<std::list<size_t>>;
    using OutputOfFunc2 = std::back_insert_iterator<std::vector<double>>;
    };

    int main()
    {
    Dijkstra<TypeDefs> d;
    }


    All that will not change anything of your binary. It only makes it a bit more convenient. But maybe I have misunderstood your question?






    share|improve this answer




























      0














      You may define all your arguments in a single structure and use them all over your structures like this:



      template<class TNode, class TEdge> class AGraph;

      template< typename TYPE_DEFS >
      class APathCalculation
      {
      using TGraph = AGraph<typename TYPE_DEFS::TNode, typename TYPE_DEFS::TEdge>;
      public:
      virtual void ReturnShortestPath(size_t source, size_t dest, TGraph& graph, typename TYPE_DEFS::OutputOfFunc1 outPath) = 0;//func1
      virtual void ReturnAllShortestDistances(size_t source, TGraph& graph, typename TYPE_DEFS::OutputOfFunc2 outDistances) = 0;//func2
      };


      template< typename TYPE_DEFS >
      class Dijkstra: public APathCalculation<TYPE_DEFS>
      {
      using TGraph = AGraph<typename TYPE_DEFS::TNode, typename TYPE_DEFS::TEdge>;
      public:
      virtual void ReturnShortestPath(size_t source, size_t dest, TGraph& graph, typename TYPE_DEFS::OutputOfFunc1 outPath) override {}
      virtual void ReturnAllShortestDistances(size_t source, TGraph& graph, typename TYPE_DEFS::OutputOfFunc2 outDistances) override {}
      };

      struct TypeDefs
      {
      using TNode = int;
      using TEdge = double;

      using OutputOfFunc1 = std::back_insert_iterator<std::list<size_t>>;
      using OutputOfFunc2 = std::back_insert_iterator<std::vector<double>>;
      };

      int main()
      {
      Dijkstra<TypeDefs> d;
      }


      All that will not change anything of your binary. It only makes it a bit more convenient. But maybe I have misunderstood your question?






      share|improve this answer


























        0












        0








        0







        You may define all your arguments in a single structure and use them all over your structures like this:



        template<class TNode, class TEdge> class AGraph;

        template< typename TYPE_DEFS >
        class APathCalculation
        {
        using TGraph = AGraph<typename TYPE_DEFS::TNode, typename TYPE_DEFS::TEdge>;
        public:
        virtual void ReturnShortestPath(size_t source, size_t dest, TGraph& graph, typename TYPE_DEFS::OutputOfFunc1 outPath) = 0;//func1
        virtual void ReturnAllShortestDistances(size_t source, TGraph& graph, typename TYPE_DEFS::OutputOfFunc2 outDistances) = 0;//func2
        };


        template< typename TYPE_DEFS >
        class Dijkstra: public APathCalculation<TYPE_DEFS>
        {
        using TGraph = AGraph<typename TYPE_DEFS::TNode, typename TYPE_DEFS::TEdge>;
        public:
        virtual void ReturnShortestPath(size_t source, size_t dest, TGraph& graph, typename TYPE_DEFS::OutputOfFunc1 outPath) override {}
        virtual void ReturnAllShortestDistances(size_t source, TGraph& graph, typename TYPE_DEFS::OutputOfFunc2 outDistances) override {}
        };

        struct TypeDefs
        {
        using TNode = int;
        using TEdge = double;

        using OutputOfFunc1 = std::back_insert_iterator<std::list<size_t>>;
        using OutputOfFunc2 = std::back_insert_iterator<std::vector<double>>;
        };

        int main()
        {
        Dijkstra<TypeDefs> d;
        }


        All that will not change anything of your binary. It only makes it a bit more convenient. But maybe I have misunderstood your question?






        share|improve this answer













        You may define all your arguments in a single structure and use them all over your structures like this:



        template<class TNode, class TEdge> class AGraph;

        template< typename TYPE_DEFS >
        class APathCalculation
        {
        using TGraph = AGraph<typename TYPE_DEFS::TNode, typename TYPE_DEFS::TEdge>;
        public:
        virtual void ReturnShortestPath(size_t source, size_t dest, TGraph& graph, typename TYPE_DEFS::OutputOfFunc1 outPath) = 0;//func1
        virtual void ReturnAllShortestDistances(size_t source, TGraph& graph, typename TYPE_DEFS::OutputOfFunc2 outDistances) = 0;//func2
        };


        template< typename TYPE_DEFS >
        class Dijkstra: public APathCalculation<TYPE_DEFS>
        {
        using TGraph = AGraph<typename TYPE_DEFS::TNode, typename TYPE_DEFS::TEdge>;
        public:
        virtual void ReturnShortestPath(size_t source, size_t dest, TGraph& graph, typename TYPE_DEFS::OutputOfFunc1 outPath) override {}
        virtual void ReturnAllShortestDistances(size_t source, TGraph& graph, typename TYPE_DEFS::OutputOfFunc2 outDistances) override {}
        };

        struct TypeDefs
        {
        using TNode = int;
        using TEdge = double;

        using OutputOfFunc1 = std::back_insert_iterator<std::list<size_t>>;
        using OutputOfFunc2 = std::back_insert_iterator<std::vector<double>>;
        };

        int main()
        {
        Dijkstra<TypeDefs> d;
        }


        All that will not change anything of your binary. It only makes it a bit more convenient. But maybe I have misunderstood your question?







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Nov 22 '18 at 15:17









        KlausKlaus

        10.9k12559




        10.9k12559























            0














            A "shallow" answer:



            In order to avoid N template parameters in one class, you need to split it into N classes with 1 template parameter each.



            A "deep" answer:



            You cannot easily combine dynamic (runtime) polymorphism of virtual functions with static (compile-time, template based) polymorphism of its argument types. If users of the APathCalculation interface want to provide their own iterator class, they will need to instantiate all the potentially useful actual implementations of this interface for their iterator class, which makes dynamic polymorphism for APathCalculation a redundant idea.



            If you really need dynamic polymorphism, you need a dynamically polymorphous iterator class.



            You can actually have both (statically polymorphous template specializations for common algorithms and/or common iterators, backed by a "default" case that is a wrapper to dynamically polymorphous implementations), but that's probably too complicated for your task. Besides, you will still need a way to bind your "default" wrapper to the actual algorithm you want the APathCalculation client to call.



            I personally would start with a purely template-based solution, but I could understand someone starting with a purely virtual function based solution.






            share|improve this answer
























            • If you really need dynamic polymorphism, you need a dynamically polymorphous iterator class. I don't understand this. Can you explain what you mean with this? How the signature in abstract class will look like in that case?

              – Dejan
              Nov 22 '18 at 16:27











            • It could be a functor (either std::function or a class with a virtual function interface), or, if you want to use in place of "normal" output iterators, it could be a wrapper class that satisfies OutputIterator requirements and redirects the required operator calls to the underlying polymorphous class (which it may hold by reference). You can look at the std::back_insert_iterator implementation in order to see which methods you need to implement.

              – Kit.
              Nov 22 '18 at 17:04


















            0














            A "shallow" answer:



            In order to avoid N template parameters in one class, you need to split it into N classes with 1 template parameter each.



            A "deep" answer:



            You cannot easily combine dynamic (runtime) polymorphism of virtual functions with static (compile-time, template based) polymorphism of its argument types. If users of the APathCalculation interface want to provide their own iterator class, they will need to instantiate all the potentially useful actual implementations of this interface for their iterator class, which makes dynamic polymorphism for APathCalculation a redundant idea.



            If you really need dynamic polymorphism, you need a dynamically polymorphous iterator class.



            You can actually have both (statically polymorphous template specializations for common algorithms and/or common iterators, backed by a "default" case that is a wrapper to dynamically polymorphous implementations), but that's probably too complicated for your task. Besides, you will still need a way to bind your "default" wrapper to the actual algorithm you want the APathCalculation client to call.



            I personally would start with a purely template-based solution, but I could understand someone starting with a purely virtual function based solution.






            share|improve this answer
























            • If you really need dynamic polymorphism, you need a dynamically polymorphous iterator class. I don't understand this. Can you explain what you mean with this? How the signature in abstract class will look like in that case?

              – Dejan
              Nov 22 '18 at 16:27











            • It could be a functor (either std::function or a class with a virtual function interface), or, if you want to use in place of "normal" output iterators, it could be a wrapper class that satisfies OutputIterator requirements and redirects the required operator calls to the underlying polymorphous class (which it may hold by reference). You can look at the std::back_insert_iterator implementation in order to see which methods you need to implement.

              – Kit.
              Nov 22 '18 at 17:04
















            0












            0








            0







            A "shallow" answer:



            In order to avoid N template parameters in one class, you need to split it into N classes with 1 template parameter each.



            A "deep" answer:



            You cannot easily combine dynamic (runtime) polymorphism of virtual functions with static (compile-time, template based) polymorphism of its argument types. If users of the APathCalculation interface want to provide their own iterator class, they will need to instantiate all the potentially useful actual implementations of this interface for their iterator class, which makes dynamic polymorphism for APathCalculation a redundant idea.



            If you really need dynamic polymorphism, you need a dynamically polymorphous iterator class.



            You can actually have both (statically polymorphous template specializations for common algorithms and/or common iterators, backed by a "default" case that is a wrapper to dynamically polymorphous implementations), but that's probably too complicated for your task. Besides, you will still need a way to bind your "default" wrapper to the actual algorithm you want the APathCalculation client to call.



            I personally would start with a purely template-based solution, but I could understand someone starting with a purely virtual function based solution.






            share|improve this answer













            A "shallow" answer:



            In order to avoid N template parameters in one class, you need to split it into N classes with 1 template parameter each.



            A "deep" answer:



            You cannot easily combine dynamic (runtime) polymorphism of virtual functions with static (compile-time, template based) polymorphism of its argument types. If users of the APathCalculation interface want to provide their own iterator class, they will need to instantiate all the potentially useful actual implementations of this interface for their iterator class, which makes dynamic polymorphism for APathCalculation a redundant idea.



            If you really need dynamic polymorphism, you need a dynamically polymorphous iterator class.



            You can actually have both (statically polymorphous template specializations for common algorithms and/or common iterators, backed by a "default" case that is a wrapper to dynamically polymorphous implementations), but that's probably too complicated for your task. Besides, you will still need a way to bind your "default" wrapper to the actual algorithm you want the APathCalculation client to call.



            I personally would start with a purely template-based solution, but I could understand someone starting with a purely virtual function based solution.







            share|improve this answer












            share|improve this answer



            share|improve this answer










            answered Nov 22 '18 at 16:18









            Kit.Kit.

            52549




            52549













            • If you really need dynamic polymorphism, you need a dynamically polymorphous iterator class. I don't understand this. Can you explain what you mean with this? How the signature in abstract class will look like in that case?

              – Dejan
              Nov 22 '18 at 16:27











            • It could be a functor (either std::function or a class with a virtual function interface), or, if you want to use in place of "normal" output iterators, it could be a wrapper class that satisfies OutputIterator requirements and redirects the required operator calls to the underlying polymorphous class (which it may hold by reference). You can look at the std::back_insert_iterator implementation in order to see which methods you need to implement.

              – Kit.
              Nov 22 '18 at 17:04





















            • If you really need dynamic polymorphism, you need a dynamically polymorphous iterator class. I don't understand this. Can you explain what you mean with this? How the signature in abstract class will look like in that case?

              – Dejan
              Nov 22 '18 at 16:27











            • It could be a functor (either std::function or a class with a virtual function interface), or, if you want to use in place of "normal" output iterators, it could be a wrapper class that satisfies OutputIterator requirements and redirects the required operator calls to the underlying polymorphous class (which it may hold by reference). You can look at the std::back_insert_iterator implementation in order to see which methods you need to implement.

              – Kit.
              Nov 22 '18 at 17:04



















            If you really need dynamic polymorphism, you need a dynamically polymorphous iterator class. I don't understand this. Can you explain what you mean with this? How the signature in abstract class will look like in that case?

            – Dejan
            Nov 22 '18 at 16:27





            If you really need dynamic polymorphism, you need a dynamically polymorphous iterator class. I don't understand this. Can you explain what you mean with this? How the signature in abstract class will look like in that case?

            – Dejan
            Nov 22 '18 at 16:27













            It could be a functor (either std::function or a class with a virtual function interface), or, if you want to use in place of "normal" output iterators, it could be a wrapper class that satisfies OutputIterator requirements and redirects the required operator calls to the underlying polymorphous class (which it may hold by reference). You can look at the std::back_insert_iterator implementation in order to see which methods you need to implement.

            – Kit.
            Nov 22 '18 at 17:04







            It could be a functor (either std::function or a class with a virtual function interface), or, if you want to use in place of "normal" output iterators, it could be a wrapper class that satisfies OutputIterator requirements and redirects the required operator calls to the underlying polymorphous class (which it may hold by reference). You can look at the std::back_insert_iterator implementation in order to see which methods you need to implement.

            – Kit.
            Nov 22 '18 at 17:04




















            draft saved

            draft discarded




















































            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.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53432489%2favoid-accumulation-of-iterator-types-in-template-arguments%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            To store a contact into the json file from server.js file using a class in NodeJS

            Redirect URL with Chrome Remote Debugging Android Devices

            Dieringhausen