16

After having found answers to many of my questions on stackoverflow, I have now come up against a question of which I can't find the answer and I hope that someone is willing to help me!

My problem is that I want to do an explicit templatization of a function inside a class in C++. My compiler (g++) and a look in the C++ standard (§14.7.3) tells me that this specialization has to be done in the namespace in which the class is declared. I understand that this implies that I cannot put the specialization inside the class, but I don't see the point of this restriction! Does anyone know if there is a good reason for not letting the specializations be made inside the class?

I know that there are workarounds, e.g. to put the function inside a struct, but I want to understand why the language has this design. If there is a good reason for not allowing specialized functions inside the class, I guess I should know it before trying to work around it.

Thanks in advance!


To make my question a little bit more precise: Here is some code from a test example which illustrates what I want to do:

#include <cstdio>

namespace MalinTester {

template <size_t DIMENSIONALITY>
class SpecializationTest {
public:
    SpecializationTest() {
        privateVariable = 5;
    };
    virtual ~SpecializationTest() {};

    void execute() {
        execute<DIMENSIONALITY>();
    };

private:
    int privateVariable;
    template <size_t currentDim>
    static void execute() {
        printf("This is the general case. Current dim is %d. The private variable is %d.\n", currentDim, privateVariable);
        execute<currentDim-1>();
    }

    template <>
    static void execute<0>() {
        printf("This is the base case. Current dim is 0.\n");
    }

};

This is not possible; g++ says:

SpecializationTest_fcn.h:27: error: explicit specialization in non-namespace scope ‘class MalinTester::SpecializationTest<DIMENSIONALITY>’
SpecializationTest_fcn.h:28: error: template-id ‘execute<0>’ in declaration of primary template

If I put the function execute outside the class, in the name space MalinTester, it will look like this:

#include <cstdio>

namespace MalinTester {

    template <size_t DIMENSIONALITY> class SpecializationTest {};

    template <size_t currentDim>
    void execute() {
        printf("This is the general case. Current dim is %d. The private variable is %d.\n", currentDim, privateVariable);
        execute<currentDim-1>();
    }

    template <>
    void execute<0>() {
        printf("This is the base case. Current dim is 0.\n");
    }

    template <size_t DIMENSIONALITY>
    class SpecializationTest {
    public:
        SpecializationTest() {};
        virtual ~SpecializationTest() {};

        void execute() {
            MalinTester::execute<DIMENSIONALITY>();
        };
    private:
        int privateVariable = 5;
    };
};
};

and I cannot use privatevariable in the templatized versions of execute, as it is private in the class. I really want it private, as I want to have my data encapsulated as far as possible.

Of course I can send privateVariable as an argument to the function, but I think it would be more beautiful to avoid this, and what I really wonder is if there is a good reason for the C++ standard not to allow explicit specialization as in the first code example above.


@Arne Mertz: This is the workaround I have tried, but it doesn't allow using privateVariable either. And most of all, I wonder if it is a good idea to do like this. As I'm not allowed to make specializations of member functions, maybe I shouldn't do specializations of functions encapsulated in structs inside the class either.

#include <cstdio>

namespace MalinTester {

template <size_t DIMENSIONALITY>
class SpecializationTest {
public:
    SpecializationTest() {
        privateVariable = 5;
    };
    virtual ~SpecializationTest() {};

    void execute() {
        Loop<DIMENSIONALITY, 0>::execute();
    };

private:
    int privateVariable;

    template <size_t currentDim, size_t DUMMY>
    struct Loop {
        static void execute() {
            printf("This is the general case. Current dim is %d.\n", currentDim);
            Loop<currentDim-1, 0>::execute();
        }
    };

    template <size_t DUMMY>
    struct Loop<0, DUMMY> {
        static void execute() {
            printf("This is the base case. Current dim is 0.\n");
        }
    };
};
};
Brad Larson
  • 170,088
  • 45
  • 397
  • 571
Malin
  • 771
  • 1
  • 7
  • 16
  • Relevant, I think. http://stackoverflow.com/questions/18294990/why-can-templatet-but-not-template-be-defined-outside-of-a-namespace-block/ – Rapptz Sep 02 '13 at 09:35
  • What exact problem is there to work around? Can't you just put the specialization in the namespace? – n. m. could be an AI Sep 02 '13 at 09:38
  • n.m.: I want to use the instance variables of the class in the functions. If I put the specialization in the namespace, outside the class, the function doesn't have access to these (unless I send an instance of the actual class as an argument to the function, but in my opinion, that makes the code uglier.) – Malin Sep 02 '13 at 09:47
  • jrok: I'm not sure I understand what you mean. I want a member function to be templatized, but it seems impossible as I can't declare a templatized member function inside the class. – Malin Sep 02 '13 at 09:50
  • @Malin Who said you can't use instance variables? [See this.](http://coliru.stacked-crooked.com/a/a3cd0fc61501671f) – jrok Sep 02 '13 at 09:52
  • In a function outside the scope of the class, I don't have access to the instance variables. I don't want to declare them as public, as I want data encapsulated as far as possible. – Malin Sep 02 '13 at 09:56
  • @jrok Agreed. [Likewise, this](http://ideone.com/V6j9s3). Or maybe I'm missing the OP's suspect restriction. – WhozCraig Sep 02 '13 at 09:58
  • Can you show the code which "does not have access?" There's probably some problem with it, because a specialisation of a member function template *does* have access to other members of its enclosing class. – Angew is no longer proud of SO Sep 02 '13 at 09:59
  • You misunderstand what the standard says. You do have access. Try writing some code, if it does not compile, ask a question and show the code. – n. m. could be an AI Sep 02 '13 at 10:00
  • Please provide some code, depicting what you *would like* to do, and what the (seemingly not working) workaround looks like. – Arne Mertz Sep 02 '13 at 10:06
  • I think the reason to forbid explicit specializations of member templates *within* the definition of an enclosing class template is the same reason why you may not explicitly specialize member templates of unspecialized class templates in namespace scope (i.e. `template template<> void SpecializationTest::execute<0>();` is [forbidden](http://coliru.stacked-crooked.com/A/3315eee536f1873f)) [temp.expl.spec]/16. – dyp Sep 02 '13 at 17:09
  • Quoted from the question text: "@Arne Mertz: This is the workaround I have tried, but it doesn't allow using privateVariable either." I think the problem here is a missconception of the scope of static member functions. Such functions lack the implicit pointer to an instance of the enclosing class, a.k.a. "this", that means it can NEVER *implicitly* access any member of its class, public or not, without a reference to an object of that class. Being a member function gives it though access to all of its members, provided it has access to a reference of an instance of that class. – brunocodutra Sep 02 '13 at 19:22
  • An almost duplicate of this question http://stackoverflow.com/questions/2537716/why-is-partial-specialziation-of-a-nested-class-template-allowed-while-complete, the difference being we are dealing with functions in this case, which nonetheless work in the exact same way as types for what matters here, aside from the further simplification that function templates do not allow partial specializations, while types do. – brunocodutra Sep 02 '13 at 19:43
  • @DyP: "I think the reason to forbid explicit specializations of member templates within the definition of an enclosing class template is the same reason why you may not explicitly specialize member templates of unspecialized class templates in namespace scope" <- OK, and why is that forbidden, then? :-P – Malin Sep 03 '13 at 07:02
  • @brunocodutra: I know, but as this is the very innermost part of a very performance critical code, I don't want to instantiate structs if it's not needed. (I know, it might be a good idea to make the public method execute static as well in order to avoid instantiating the class, and send privateVariable as an argument, but that's the next step. Now I want to understand why the C++ standard has this, in my eyes, limitation.) – Malin Sep 03 '13 at 07:09
  • @brunocodutra I hadn't seen the discussion to which you refer, thank you. You mean that the reason is simply to make life easier for compiler writers? – Malin Sep 03 '13 at 07:15
  • @Malin Part of the rationale I had in mind is given by [the answer](http://stackoverflow.com/a/2537825/420683) of the question brunocodutra linked: An explicitly specialized function template is a function, not a template any more; but an explicitly specialized function template *inside* a not fully specialized class template still had to be a template. It's not completely about compiler writers, though, as instantiation rules for template members of class templates are vastly different from explicit specializations of those members (i.e. allowing it would result in more complicated rules). – dyp Sep 03 '13 at 12:55
  • @Malin I believe so, but that is not such a simple matter as it sounds, because there's no point in specifying a complex behavior which no compiler developer is going to be able to implement. This happened with the keyword `export` and its associated behavior: for years no major compiler had implemented it, to the point the commitee voted for deprecating it when voted for the c++11 standard. While I do not know for sure if the same rationale applies here, I think it is at least fair to consider the complexity of implementation, when voting for a new feature. – brunocodutra Sep 03 '13 at 20:44

1 Answers1

7

Base specialization:

In .h:

template <class T>
class UISelectorSlider :  public UISelectorFromRange<T> {
public:
    UISelectorSlider();
    virtual ~UISelectorSlider();
private:
    float width;
    float getPositionFromValue(T value);
};

In .cpp under same namespace:

template <>
float UISelectorSlider<MVHue>::getPositionFromValue(MVHue value)
{
    return width * (float)value / 360.0;
}

If you want specialized function within specialized class:

Inside class add (.h) (private function):

private:
    template <int I>
    void foo();

Specialization inside .cpp:

template <>
template <>
void UISelectorSlider<MVHue>::foo<3>()
{
     // you can access private fields here
}

UPDATE:

But you cant write something like this:

template <class T>
template <>
void UISelectorSlider<T>::foo<3>()
{
     // you can access private fields here
}

You will get: error: enclosing class templates are not explicitly specialized.

It does not matter is this definition inside class or in namespace. The point is that this is not exact partial specialization - this function does not have defined context class (which members you want to call). In other words - when you specialize member you actually try specialize the whole containing class, but not the member itself. And compiler cant do that because class is not yet defined completely. So this is restriction by template design. And if it actually worked - templates would be full equivalent to simple macros. (And you probably can will solve your task with some macro magic.)

Victor Laskin
  • 2,577
  • 2
  • 16
  • 10
  • 7
    I appreciate that people are willing to answer, but my question is **if there is a good reason for the standard not allowing specializations of a templatized function inside a class**, not how to work around it. (Moreover, I want to encapsulate the function in the class!) – Malin Sep 03 '13 at 10:45