views:

149

answers:

2

I have a static Utils class. I want certain methods to be templated, but not the entire class. How do I do this?

This fails:

#pragma once

#include <string>
using std::string;

class Utils
{
private:
    template<class InputIterator, class Predicate>
    static set<char> findAll_if_rec(InputIterator begin, InputIterator end, Predicate pred, set<char> result);

public:
    static void PrintLine(const string& line, int tabLevel = 0);
    static string getTabs(int tabLevel);

    template<class InputIterator, class Predicate>
    static set<char> Utils::findAll_if(InputIterator begin, InputIterator end, Predicate pred);
};

Error:

utils.h(10): error C2143: syntax error : missing ';' before '<'
utils.h(10): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
utils.h(10): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
utils.h(10): error C2238: unexpected token(s) preceding ';'
utils.h(10): error C2988: unrecognizable template declaration/definition
utils.h(10): error C2059: syntax error : '<'

What am I doing wrong? What is the correct syntax for this?

Incidentally, I'd like to templatize the return value, too. So instead of:

template<class InputIterator, class Predicate>
static set<char> findAll_if_rec(InputIterator begin, InputIterator end, Predicate pred, set<char> result);

I'd have:

template<class return_t, class InputIterator, class Predicate>
static return_t findAll_if_rec(InputIterator begin, InputIterator end, Predicate pred, set<char> result);

How would I specify that:

1) return_t must be a set of some sort

2) InputIterator must be an iterator

3) InputIterator's type must work with return_t's type.

Thanks.

UPDATE: In response to people who say I should use a namespace intsead of a Java/C# style Utils class, is this more what you were looking for:

Utils.h

#pragma once

#include <string>
#include <set>
using std::set;
using std::string;

namespace Utils
{
    static void PrintLine(const string& line, int tabLevel = 0);
    static string getTabs(int tabLevel);

    template<class result_t, class Predicate>
    set<result_t> Utils::findAll_if(set<result_t>::iterator begin, set<result_t>::iterator end, Predicate pred);
};

Utils.cpp

#include "Utils.h"
#include <iostream>
#include <string>
using std::string;
using std::cout;
using std::endl;

void Utils::PrintLine(const string& line, int tabLevel)
{
    string tabs = getTabs(tabLevel);

    cout << tabs << line << endl;
}

string Utils::getTabs(int tabLevel)
{
    string tabs;
    while (tabLevel != 0)
    {
        tabs += "\t";
        tabLevel--;
    }
    return tabs;
}

template<class result_t, class Predicate>
set<result_t> Utils::findAll_if(set<result_t>::iterator begin, set<result_t>::iterator end, Predicate pred)
{
    set<char> result;
    return findAll_if_rec(begin, end, pred, result);
}

template<class result_t, class Predicate>
set<result_t> findAll_if_rec(set<result_t>::iterator begin, set<result_t>::iterator end, Predicate pred, set<result_t> result)
{
    InputIterator nextResultElem = find_if(begin, end, pred);
    if (nextResultElem == end)
    {
        return result;
    }
    result.add(*nextResultElem);

    return findAll_if_rec(++nextResultElem, end, pred, result);
}

This has many compiler errors. I don't think I'm using the result_t template argument correctly.

Update 2 Based on Georg's comments:

Utils.h

#pragma once

#include <string>
#include <set>
using std::set;
using std::string;

namespace Utils
{
    void PrintLine(const string& line, int tabLevel = 0);
    string getTabs(int tabLevel);

    template<class result_t, class Predicate>
    set<result_t> Utils::findAll_if(set<result_t>::iterator begin, set<result_t>::iterator end, Predicate pred);
};

namespace detail
{
    template<class result_t, class Predicate>
    set<result_t> findAll_if_rec(set<result_t>::iterator begin, set<result_t>::iterator end, Predicate pred, set<result_t> result);
};

Utils.cpp

#include "Utils.h"
#include <iostream>
#include <string>
using std::string;
using std::cout;
using std::endl;

void Utils::PrintLine(const string& line, int tabLevel)
{
    string tabs = getTabs(tabLevel);

    cout << tabs << line << endl;
}

string Utils::getTabs(int tabLevel)
{
    string tabs;
    while (tabLevel != 0)
    {
        tabs += "\t";
        tabLevel--;
    }
    return tabs;
}

set<result_t> Utils::findAll_if(set<result_t>::iterator begin, set<result_t>::iterator end, Predicate pred)
{
    set<char> result;
    return findAll_if_rec(begin, end, pred, result);
}

set<result_t> detail::findAll_if_rec(set<result_t>::iterator begin, set<result_t>::iterator end, Predicate pred, set<result_t> result)
{
    InputIterator nextResultElem = find_if(begin, end, pred);
    if (nextResultElem == end)
    {
        return result;
    }
    result.add(*nextResultElem);

    return findAll_if_rec(++nextResultElem, end, pred, result);
}

Still not compiling. Help?

Update 3: Getting closer...

Utils.h:

#pragma once

#include <string>
#include <set>
using std::set;
using std::string;

namespace Utils
{
    void PrintLine(const string& line, int tabLevel = 0);
    string getTabs(int tabLevel);

    template<class result_t, class Predicate>
    set<result_t> Utils::findAll_if(set<result_t>::iterator begin, set<result_t>::iterator end, Predicate pred)
    {
        set<result_t> result;
        return findAll_if_rec(begin, end, pred, result);
    }
}

namespace detail
{
    template<class result_t, class Predicate>
    set<result_t> findAll_if_rec(set<result_t>::iterator begin, set<result_t>::iterator end, Predicate pred, set<result_t> result)
    {
        set<result_t>::iterator nextResultElem = find_if(begin, end, pred);
        if (nextResultElem == end)
        {
            return result;
        }
        result.add(*nextResultElem);

        return findAll_if_rec(++nextResultElem, end, pred, result);
    }
}

Utils.cpp:

#include "Utils.h"
#include <iostream>
#include <string>
using std::string;
using std::cout;
using std::endl;

void Utils::PrintLine(const string& line, int tabLevel)
{
    string tabs = getTabs(tabLevel);

    cout << tabs << line << endl;
}

string Utils::getTabs(int tabLevel)
{
    string tabs;
    while (tabLevel != 0)
    {
        tabs += "\t";
        tabLevel--;
    }
    return tabs;
}

Still doesn't compile.

+4  A: 

It's complaining about the return type--set<char>: you forgot to include <set> and use using std::set (or preferably, just type out std::set where you use it).

As for forcing a template argument to meet certain requirements, the easiest way is just to write your code such that it assumes the type meets those requirements. If the type doesn't meet those requirements, compilation will fail.

James McNellis
A: 

If you always want to return as set, then you can make your function return a set whose template parameter is a template parameter of your function:

template<class set_t, class InputIterator, class Predicate>
static std::set<set_t> findAll_if_rec(InputIterator begin, InputIterator end, Predicate pred, std::set<set_t> result);
Aaron Klotz