1

Is it possible to use a class template as parameter in a template specialization?

I would like to be able to use something like foo<Foo<int>>() (see #3 in source code) and have unique code for that template instance run. At the moment only ordinary specialization works (see #2).

A previous similar question would have me believe approach #3 would work, but the code doesn't work under msvc2012 at least.

Is what I'm trying to do possible? If so, how?

Source

// Test struct.
template<class T>
struct Foo
{
    T foo;
};

// #1 Ordinary template
template<class T>
T foo()
{
    return T();
}

// #2 Template specialization
template<>
int foo<int>()
{
    return 42;
}

// #3 Template specialization with template as parameter? Not working.
template<>
template<typename T>
Foo<T> foo<Foo<T>>()
{
    return Foo<T>();
}
Community
  • 1
  • 1
Adelost
  • 2,343
  • 2
  • 23
  • 28
  • 1
    Clang gives a nice clear warning about the extra `typename<>`. Anyway, you can't partially specialize function templates. But you can partially specialize class templates. – chris Jun 21 '14 at 16:49
  • I agree, this won't work with functions. Wrap it up – Marco A. Jun 21 '14 at 16:50
  • 1
    *"template class"* The correct term is *class template*. Its a template to generate classes. – Manu343726 Jun 21 '14 at 17:02
  • Thanks for the info, I will refer to it as a "class template" from now on. – Adelost Jun 21 '14 at 17:24

2 Answers2

2

Functions can't be partially specialized, you need to wrap it up into a class or struct

#include <iostream>
using namespace std;

// Test struct.
template<class T>
struct Foo
{
    T foo;
};

// Struct specialization
template<>
struct Foo<bool>
{
    static const int val = 46;
};

// #1 Ordinary template
template<class T>
struct functionWrapper {
    static T foo() {
        return T();
    }
};

// #2 Template specialization
template<>
struct functionWrapper<int> {
    static int foo() {
        return 42;
    }
};

// #3 Template specialization with template as parameter
template<class T>
struct functionWrapper<struct Foo<T>> {
    static Foo<T>* foo() {
        return new Foo<T>();
    }
};

int main() {
    cout << functionWrapper<bool>::foo() << endl;
    cout << functionWrapper<int>::foo() << endl;

    Foo<bool> *obj = functionWrapper<Foo<bool>>::foo();
    cout << obj->val;
    delete obj; // Always be a good citizen

    return 0;
}

http://ideone.com/8TXJH4

Marco A.
  • 43,032
  • 26
  • 132
  • 246
  • Thanks for the solution. However, I'm a bit confused why class templates should behave differently from function templates. I hope the change it in future C++ versions. – Adelost Jun 21 '14 at 17:45
  • Also, I find allocating Foo on the heap a bit unnecessary. But I do want to be a good citizen. :) – Adelost Jun 21 '14 at 17:51
  • 1
    @Adelost allocating it on the heap was just a decision I took "without thinking too much" to have the sample working. You can change it if you want but watch out for the scope of the objects you use/return (and if you copy them into the destination). As for the functions partial specialization AFAIK the standard decided not to support them because they would introduce additional complexity and intrinsic problems (google for Dimov/Abrahams problem and you'll get a sample of what I'm talking about). – Marco A. Jun 21 '14 at 17:53
0

I rewrote Marco A.'s solution to allow me to keep my original syntax.

Then, I also came up with a second solution which uses "out parameters" instead of "return values". I think this solution is is better as it is simper to maintain and accomplishes the same job.

Solution #1 (Rewritten Marco A's solution with original syntax)

#include <iostream>
using namespace std;

// Test struct
template<class T>
struct Foo
{
    T foo;
};

// #1 Ordinary template
template<class T>
struct FooWrapper
{
    static T foo()
    {
        return T();
    }
};

// #2 Template specialization
template<>
struct FooWrapper<int>
{
    static int foo()
    {
        return 42;
    }
};

// #3 Template specialization with template as parameter
template<class T>
struct FooWrapper<Foo<T>>
{
    static Foo<T> foo()
    {
        return Foo<T>();
    }
};

// Hides wrapper implementation
template<class T>
T foo()
{
    return FooWrapper<T>::foo();
}

int main()
{
    cout << foo<bool>() << endl;
    cout << foo<int>() << endl;
    cout << foo<Foo<int>>().foo << endl;

    return 0;
}

Solution #2 (Simpler, possible better solution using out parameters)

#include <iostream>
using namespace std;

// Test struct
template<class T>
struct Foo
{
    T foo;
    int bar;
};

// #1 General case
template<class T>
void foo(T& value)
{
    value = T();
}

// #2 Special case
void foo(int& value)
{
    value = 2;
}

// #3 Special case with class template
template<class T>
void foo(Foo<T>& value)
{
    value.bar = 3;
}

// Function templates with hidden specializations
template<class T>
T foo()
{
    T value;
    foo(value);

    return value;
}

int main()
{
    cout << foo<bool>() << endl;
    cout << foo<int>() << endl;
    cout << foo<Foo<int>>().bar << endl;

    return 0;
}
Adelost
  • 2,343
  • 2
  • 23
  • 28