Why function template cannot be partially specialized? - c++

I know the language specification forbids partial specialization of function template.
I would like to know the rationale why it forbids it? Are they not useful?
template<typename T, typename U> void f() {} //allowed!
template<> void f<int, char>() {} //allowed!
template<typename T> void f<char, T>() {} //not allowed!
template<typename T> void f<T, int>() {} //not allowed!

AFAIK that's changed in C++0x.
I guess it was just an oversight (considering that you can always get the partial specialization effect with more verbose code, by placing the function as a static member of a class).
You might look up the relevant DR (Defect Report), if there is one.
EDIT: checking this, I find that others have also believed that, but no-one is able to find any such support in the draft standard. This SO thread seems to indicate that partial specialization of function templates is not supported in C++0x.
EDIT 2: just an example of what I meant by "placing the function as a static member of a class":
#include <iostream>
using namespace std;
// template<typename T, typename U> void f() {} //allowed!
// template<> void f<int, char>() {} //allowed!
// template<typename T> void f<char, T>() {} //not allowed!
// template<typename T> void f<T, int>() {} //not allowed!
void say( char const s[] ) { std::cout << s << std::endl; }
namespace detail {
template< class T, class U >
struct F {
static void impl() { say( "1. primary template" ); }
};
template<>
struct F<int, char> {
static void impl() { say( "2. <int, char> explicit specialization" ); }
};
template< class T >
struct F< char, T > {
static void impl() { say( "3. <char, T> partial specialization" ); }
};
template< class T >
struct F< T, int > {
static void impl() { say( "4. <T, int> partial specialization" ); }
};
} // namespace detail
template< class T, class U >
void f() { detail::F<T, U>::impl(); }
int main() {
f<char const*, double>(); // 1
f<int, char>(); // 2
f<char, double>(); // 3
f<double, int>(); // 4
}

Well, you really can't do partial function/method specialization however you can do overloading.
template <typename T, typename U>
T fun(U pObj){...}
// acts like partial specialization <T, int> AFAIK
// (based on Modern C++ Design by Alexandrescu)
template <typename T>
T fun(int pObj){...}
It is the way but I do not know if it satisfy you.

In general, it's not recommended to specialize function templates at all, because of troubles with overloading. Here's a good article from the C/C++ Users Journal: http://www.gotw.ca/publications/mill17.htm
And it contains an honest answer to your question:
For one thing, you can't partially specialize them -- pretty much just because the language says you can't.

Since you can partially specialize classes, you can use a functor:
#include <iostream>
template <typename dtype, int k> struct fun
{
int operator()()
{
return k;
}
};
template <typename dtype> struct fun <dtype, 0>
{
int operator()()
{
return 42;
}
};
int main ( int argc , char * argv[] )
{
std::cout << fun<float, 5>()() << std::endl;
std::cout << fun<float, 0>()() << std::endl;
}

Related

Explicit template specialization cannot have a storage class - member method specialization

Say I have the following code in Visual Studio
class foo
{
public:
template<typename t>
void foo_temp(int a , t s_)
{
std::cout << "This is general tmeplate method";
}
template<>
static void foo_temp(int a , int s)
{
std::cout << "This is a specialized method";
}
};
int main()
{
foo f;
f.foo_temp<std::string>(12,"string");
}
Now I am attempting to covert this into GCC. Going through other questions on SO I noticed that in GCC member methods cannot be specialized if the class is not specialized. I therefore came up with this solution
class foo
{
public:
template<typename t>
void foo_temp(int a , t s_)
{
std::cout << "This is general template method";
}
};
template <>
/*static*/ void foo::foo_temp<int>(int a, int value) {
std::cout << "Hello world";
}
Now this seems to do the trick however when I include the static keyword into the statement i get the error
explicit template specialization cannot have a storage class
Now this thread talks about it but I am still confused on how I could apply that here. Any suggestions on how I can make the last method static ? Also I am still confused as to why templated methods cant be static in GCC ?
This is the visual studio code
class foo
{
public:
template<typename t>
void foo_temp(int a , t s_)
{
std::cout << "This is general tmeplate method";
}
template<>
static void foo_temp(int a , int s)
{
std::cout << "This is a specialized method";
}
};
int main()
{
foo f;
f.foo_temp<std::string>(12,"string");
}
Any suggestions on how I can make the last method static?
You can't; it's unsupported by the language.
Also I am still confused as to why templated methods cant be static in GCC?
They can; they just can't be both static and non-static. Example:
struct foo {
template<typename T>
void bar() {}
template<typename T>
static void baz() {}
};
int main() {
foo f;
f.template bar<void>();
foo::baz<void>();
}
It's very confusing to me why you must have a static specialization of a (non-static) template member function. I would seriously re-evaluate this code for sanity.
Note, to the question in the comments, it is not possible to have a template specialization of a static member function, because it is not possible to have a template specialization of a member function in this situation at all. (Use overloading instead.)
struct foo {
template<typename T, typename U>
static void bar(T, U) {}
// Error, you'd need to also specialize the class, which requires a template class, we don't have one.
// template<>
// static void bar(int, int) {}
// test.cpp:2:12: error: explicit specialization of non-template ‘foo’
// 2 | struct foo {
// | ^
// Partial specializations aren't allowed even in situations where full ones are
// template<typename U>
// static void bar<int, U>(int, U) {}
// test.cpp:14:33: error: non-class, non-variable partial specialization ‘bar<int, U>’ is not allowed
// 14 | static void bar<int, U>(int, U) {}
// | ^
// Instead just overload
template<typename U>
static void bar(int, U) {}
};
Did you try good old fashioned overloading? Don't make the static method a template at all and let overloading priority take care of picking it.
The static method isn't the problem here, the template<> declaration inside a class is the main culprit. You can't declare specialized template inside a class. you can use namespace instead:
namespace foo{
template<typename t>
void foo_temp(int a , t s_)
{
std::cout << "This is general tmeplate method";
}
template<>
void foo_temp(int a , int s)
{
std::cout << "This is a specialized method";
}
}
int main()
{
foo::foo_temp<int>(12,7);
}
Or you can use it inside class like this:
class foo
{
public:
template<typename t>
void foo_temp(int a , t s_)
{
std::cout << "This is general tmeplate method";
}
static void foo_temp(int a , int s)
{
std::cout << "This is a specialized method";
}
};
int main()
{
foo f;
f.foo_temp(12,"string");
f.foo_temp(12,6);
}
N.B: you should call both function (at least the second one) like f.foo_temp(a,b) instead of f.foo_temp<int>() in this case.

Specializing a method template for classes in a namespace

I'm using the following compile-time 'trick' (based on ADL) to create a function that is only valid/defined/callable by classes in the same namespace.
namespace Family1
{
struct ModelA{};
struct ModelB{};
template<typename T>
bool is_in_Family1(T const& t)
{
return true;
}
};
namespace Family2
{
struct ModelC{};
template<typename T>
bool is_in_Family2(T const& t)
{
return true;
}
};
Family1::ModelA mA;
Family2::ModelC mC;
is_in_Family1(mA); // VALID
is_in_Family1(mC); // ERROR
Now, I'd like to use this principle (or something similar) in order to produce a specialization of Foo::Bar (below) for classes belonging to each of the namespaces e.g. Family1.
// I would like to specialize the method template Bar for classes in Family1
// namespace; and another specialization for classes in Family2 namespace
struct Foo
{
template<typename T>
void Bar( T& _T ){}
};
For ease of maintenance and the large number of classes in each namespace, if possible, I'd like to perform this check without naming all the classes in a namespace.
Your "trick" has one big problem. Try calling is_in_Family1(make_pair(Family1::ModelA(), Family2::ModelC()) and you will see that return true, because ADL will look into both the namespaces of ModelA and ModelC (because of pair<ModelA, ModelC>).
Ignoring that problem, with using your functions it is straight forward.
template<typename T> struct int_ { typedef int type; };
struct Foo
{
template<typename T,
typename int_<decltype(is_in_Family1(*(T*)0))>::type = 0
>
void Bar( T& t ){}
template<typename T,
typename int_<decltype(is_in_Family2(*(T*)0))>::type = 0
>
void Bar( T& t ){}
};
That calls Bar depending on whether it is in family2 or family1.
struct Foo
{
template<typename T,
typename int_<decltype(is_in_Family1(*(T*)0))>::type = 0
>
void Bar( T& t, long){}
template<typename T,
typename int_<decltype(is_in_Family2(*(T*)0))>::type = 0
>
void Bar( T& t, long){}
template<typename T>
void Bar( T& t, int) {}
template<typename T>
void Bar( T& t ) { return Bar(t, 0); }
};
That one has also a generic fallback. And your code had undefined behavior because you used a reserved name. Don't use _T.
The quickest way I found to do this is using Boost Type Traits' is_base_of<>
I tried to use inheritence with template specialization but that didn't work because inheritance is ignored when template specialization is used so you'd have to specialize for each model. The answer to Partial specialization for a parent of multiple classes explains the problem.
Using type traits works provided you make Family1::ModelA and Family::ModelB subclasses of Family1:Family1Type and Family2::ModelC a subclass of Family2::Family2Type :
#include <iostream>
#include <boost/type_traits/is_base_of.hpp>
namespace Family1{
struct Family1Type{};
struct ModelA :public Family1Type{};
struct ModelB :public Family1Type{};
template<typename T>
bool is_in_Family1(const T& t){
return boost::is_base_of<Family1::Family1Type,T>::value;
}
};
namespace Family2{
struct Family2Type{};
struct ModelC :public Family2Type{};
template<typename T>
bool is_in_Family2(const T& t){
return boost::is_base_of<Family2::Family2Type,T>::value;
}
};
using namespace std;
int main(int argc, char *argv[]) {
Family1::ModelA mA;
Family2::ModelC mC;
std::cout << "mA is in Family1? " << is_in_Family1(mA) << std::endl;
std::cout << "mC is in Family2? " << is_in_Family2(mC) << std::endl;
//std::cout << "mC is in Family1? " << is_in_Family1(mC) << std::endl; //ERROR!
//std::cout << "mA is in Family2? " << is_in_Family2(mA) << std::endl; //ERROR!
return 0;
}
This results in the following output:
mA is in Family1? 1
mC is in Family2? 1
I don't think there is a way to declare Foo and specialize Foo::Bar<> in another namespace according to Specialization of 'template<class _Tp> struct std::less' in different namespace

Detecting a function in C++ at compile time

Is there a way, presumably using templates, macros or a combination of the two, that I can generically apply a function to different classes of objects but have them respond in different ways if they do not have a specific function?
I specifically want to apply a function which will output the size of the object (i.e. the number of objects in a collection) if the object has that function but will output a simple replacement (such as "N/A") if the object doesn't. I.e.
NO_OF_ELEMENTS( mySTLMap ) -----> [ calls mySTLMap.size() to give ] ------> 10
NO_OF_ELEMENTS( myNoSizeObj ) --> [ applies compile time logic to give ] -> "N/A"
I expect that this might be something similar to a static assertion although I'd clearly want to compile a different code path rather than fail at build stage.
From what I understand, you want to have a generic test to see if a class has a certain member function. This can be accomplished in C++ using SFINAE. In C++11 it's pretty simple, since you can use decltype:
template <typename T>
struct has_size {
private:
template <typename U>
static decltype(std::declval<U>().size(), void(), std::true_type()) test(int);
template <typename>
static std::false_type test(...);
public:
typedef decltype(test<T>(0)) type;
enum { value = type::value };
};
If you use C++03 it is a bit harder due to the lack of decltype, so you have to abuse sizeof instead:
template <typename T>
struct has_size {
private:
struct yes { int x; };
struct no {yes x[4]; };
template <typename U>
static typename boost::enable_if_c<sizeof(static_cast<U*>(0)->size(), void(), int()) == sizeof(int), yes>::type test(int);
template <typename>
static no test(...);
public:
enum { value = sizeof(test<T>(0)) == sizeof(yes) };
};
Of course this uses Boost.Enable_If, which might be an unwanted (and unnecessary) dependency. However writing enable_if yourself is dead simple:
template<bool Cond, typename T> enable_if;
template<typename T> enable_if<true, T> { typedef T type; };
In both cases the method signature test<U>(int) is only visible, if U has a size method, since otherwise evaluating either the decltype or the sizeof (depending on which version you use) will fail, which will then remove the method from consideration (due to SFINAE. The lengthy expressions std::declval<U>().size(), void(), std::true_type() is an abuse of C++ comma operator, which will return the last expression from the comma-separated list, so this makes sure the type is known as std::true_type for the C++11 variant (and the sizeof evaluates int for the C++03 variant). The void() in the middle is only there to make sure there are no strange overloads of the comma operator interfering with the evaluation.
Of course this will return true if T has a size method which is callable without arguments, but gives no guarantees about the return value. I assume wou probably want to detect only those methods which don't return void. This can be easily accomplished with a slight modification of the test(int) method:
// C++11
template <typename U>
static typename std::enable_if<!is_void<decltype(std::declval<U>().size())>::value, std::true_type>::type test(int);
//C++03
template <typename U>
static typename std::enable_if<boost::enable_if_c<sizeof(static_cast<U*>(0)->size()) != sizeof(void()), yes>::type test(int);
There was a discussion about the abilities of constexpr some times ago. It's time to use it I think :)
It is easy to design a trait with constexpr and decltype:
template <typename T>
constexpr decltype(std::declval<T>().size(), true) has_size(int) { return true; }
template <typename T>
constexpr bool has_size(...) { return false; }
So easy in fact that the trait loses most of its value:
#include <iostream>
#include <vector>
template <typename T>
auto print_size(T const& t) -> decltype(t.size(), void()) {
std::cout << t.size() << "\n";
}
void print_size(...) { std::cout << "N/A\n"; }
int main() {
print_size(std::vector<int>{1, 2, 3});
print_size(1);
}
In action:
3
N/A
This can be done using a technique called SFINAE. In your specific case you could implement that using Boost.Concept Check. You'd have to write your own concept for checking for a size-method. Alternatively you could use an existing concept such as Container, which, among others, requires a size-method.
You can do something like
template< typename T>
int getSize(const T& t)
{
return -1;
}
template< typename T>
int getSize( const std::vector<T>& t)
{
return t.size();
}
template< typename T , typename U>
int getSize( const std::map<T,U>& t)
{
return t.size();
}
//Implement this interface for
//other objects
class ISupportsGetSize
{
public:
virtual int size() const= 0;
};
int getSize( const ISupportsGetSize & t )
{
return t.size();
}
int main()
{
int s = getSize( 4 );
std::vector<int> v;
s = getSize( v );
return 0;
}
basically the most generic implementation is always return -1 or "NA" but for vector and maps it will return the size. As the most general one always matches there is never a build time failure
Here you go. Replace std::cout with the output of your liking.
template <typename T>
class has_size
{
template <typename C> static char test( typeof(&C::size) ) ;
template <typename C> static long test(...);
public:
enum { value = sizeof(test<T>(0)) == sizeof(char) };
};
template<bool T>
struct outputter
{
template< typename C >
static void output( const C& object )
{
std::cout << object.size();
}
};
template<>
struct outputter<false>
{
template< typename C >
static void output( const C& )
{
std::cout << "N/A";
}
};
template<typename T>
void NO_OF_ELEMENTS( const T &object )
{
outputter< has_size<T>::value >::output( object );
}
You could try something like:
#include <iostream>
#include <vector>
template<typename T>
struct has_size
{
typedef char one;
typedef struct { char a[2]; } two;
template<typename Sig>
struct select
{
};
template<typename U>
static one check (U*, select<char (&)[((&U::size)!=0)]>* const = 0);
static two check (...);
static bool const value = sizeof (one) == sizeof (check (static_cast<T*> (0)));
};
struct A{ };
int main ( )
{
std::cout << has_size<int>::value << "\n";
std::cout << has_size<A>::value << "\n";
std::cout << has_size<std::vector<int>>::value << "\n";
}
but you have to be careful, this does neither work when size is overloaded, nor when it is a template. When you can use C++11, you can replace the above sizeof trick by decltype magic

c++ template specialization for all subclasses

I need to create a template function like this:
template<typename T>
void foo(T a)
{
if (T is a subclass of class Bar)
do this
else
do something else
}
I can also imagine doing it using template specialization ... but I have never seen a template specialization for all subclasses of a superclass. I don't want to repeat specialization code for each subclass
You can do what you want but not how you are trying to do it! You can use std::enable_if together with std::is_base_of:
#include <iostream>
#include <utility>
#include <type_traits>
struct Bar { virtual ~Bar() {} };
struct Foo: Bar {};
struct Faz {};
template <typename T>
typename std::enable_if<std::is_base_of<Bar, T>::value>::type
foo(char const* type, T) {
std::cout << type << " is derived from Bar\n";
}
template <typename T>
typename std::enable_if<!std::is_base_of<Bar, T>::value>::type
foo(char const* type, T) {
std::cout << type << " is NOT derived from Bar\n";
}
int main()
{
foo("Foo", Foo());
foo("Faz", Faz());
}
Since this stuff gets more wide-spread, people have discussed having some sort of static if but so far it hasn't come into existance.
Both std::enable_if and std::is_base_of (declared in <type_traits>) are new in C++2011. If you need to compile with a C++2003 compiler you can either use their implementation from Boost (you need to change the namespace to boost and include "boost/utility.hpp" and "boost/enable_if.hpp" instead of the respective standard headers). Alternatively, if you can't use Boost, both of these class template can be implemented quite easily.
I would use std::is_base_of along with local class as :
#include <type_traits> //you must include this: C++11 solution!
template<typename T>
void foo(T a)
{
struct local
{
static void do_work(T & a, std::true_type const &)
{
//T is derived from Bar
}
static void do_work(T & a, std::false_type const &)
{
//T is not derived from Bar
}
};
local::do_work(a, std::is_base_of<Bar,T>());
}
Please note that std::is_base_of derives from std::integral_constant, so an object of former type can implicitly be converted into an object of latter type, which means std::is_base_of<Bar,T>() will convert into std::true_type or std::false_type depending upon the value of T. Also note that std::true_type and std::false_type are nothing but just typedefs, defined as:
typedef integral_constant<bool, true> true_type;
typedef integral_constant<bool, false> false_type;
I know this question has been answered but nobody mentioned that std::enable_if can be used as a second template parameter like this:
#include <type_traits>
class A {};
class B: public A {};
template<class T, typename std::enable_if<std::is_base_of<A, T>::value, int>::type = 0>
int foo(T t)
{
return 1;
}
I like this clear style:
void foo_detail(T a, const std::true_type&)
{
//do sub-class thing
}
void foo_detail(T a, const std::false_type&)
{
//do else
}
void foo(T a)
{
foo_detail(a, std::is_base_of<Bar, T>::value);
}
The problem is that indeed you cannot do something like this in C++17:
template<T>
struct convert_t {
static auto convert(T t) { /* err: no specialization */ }
}
template<T>
struct convert_t<T> {
// T should be subject to the constraint that it's a subclass of X
}
There are, however, two options to have the compiler select the correct method based on the class hierarchy involving tag dispatching and SFINAE.
Let's start with tag dispatching. The key here is that tag chosen is a pointer type. If B inherits from A, an overload with A* is selected for a value of type B*:
#include <iostream>
#include <type_traits>
struct type_to_convert {
type_to_convert(int i) : i(i) {};
type_to_convert(const type_to_convert&) = delete;
type_to_convert(type_to_convert&&) = delete;
int i;
};
struct X {
X(int i) : i(i) {};
X(const X &) = delete;
X(X &&) = delete;
public:
int i;
};
struct Y : X {
Y(int i) : X{i + 1} {}
};
struct A {};
template<typename>
static auto convert(const type_to_convert &t, int *) {
return t.i;
}
template<typename U>
static auto convert(const type_to_convert &t, X *) {
return U{t.i}; // will instantiate either X or a subtype
}
template<typename>
static auto convert(const type_to_convert &t, A *) {
return 42;
}
template<typename T /* requested type, though not necessarily gotten */>
static auto convert(const type_to_convert &t) {
return convert<T>(t, static_cast<T*>(nullptr));
}
int main() {
std::cout << convert<int>(type_to_convert{5}) << std::endl;
std::cout << convert<X>(type_to_convert{6}).i << std::endl;
std::cout << convert<Y>(type_to_convert{6}).i << std::endl;
std::cout << convert<A>(type_to_convert{-1}) << std::endl;
return 0;
}
Another option is to use SFINAE with enable_if. The key here is that while the snippet in the beginning of the question is invalid, this specialization isn't:
template<T, typename = void>
struct convert_t {
static auto convert(T t) { /* err: no specialization */ }
}
template<T>
struct convert_t<T, void> {
}
So our specializations can keep a fully generic first parameter as long we make sure only one of them is valid at any given point. For this, we need to fashion mutually exclusive conditions. Example:
template<typename T /* requested type, though not necessarily gotten */,
typename = void>
struct convert_t {
static auto convert(const type_to_convert &t) {
static_assert(!sizeof(T), "no conversion");
}
};
template<>
struct convert_t<int> {
static auto convert(const type_to_convert &t) {
return t.i;
}
};
template<typename T>
struct convert_t<T, std::enable_if_t<std::is_base_of_v<X, T>>> {
static auto convert(const type_to_convert &t) {
return T{t.i}; // will instantiate either X or a subtype
}
};
template<typename T>
struct convert_t<T, std::enable_if_t<std::is_base_of_v<A, T>>> {
static auto convert(const type_to_convert &t) {
return 42; // will instantiate either X or a subtype
}
};
template<typename T>
auto convert(const type_to_convert& t) {
return convert_t<T>::convert(t);
}
Note: the specific example in the text of the question can be solved with constexpr, though:
template<typename T>
void foo(T a) {
if constexpr(std::is_base_of_v<Bar, T>)
// do this
else
// do something else
}
If you are allowed to use C++20 concepts, all this becomes almost trivial:
template<typename T> concept IsChildOfX = std::is_base_of<X, T>::value;
// then...
template<IsChildOfX X>
void somefunc( X& x ) {...}

SFINAE: detect if class has free function

Is there a way, using SFINAE, to detect whether a free function is overloaded for a given class?
Basically, I’ve got the following solution:
struct has_no_f { };
struct has_f { };
void f(has_f const& x) { }
template <typename T>
enable_if<has_function<T, f>::value, int>::type call(T const&) {
std::cout << "has f" << std::endl;
}
template <typename T>
disable_if<has_function<T, f>::value, int>::type call(T const&) {
std::cout << "has no f" << std::endl;
}
int main() {
call(has_no_f()); // "has no f"
call(has_f()); // "has f"
}
Simply overloading call doesn’t work since there are actually a lot of foo and bar types and the call function has no knowledge of them (basically call is inside a and the users supply their own types).
I cannot use C++0x, and I need a working solution for all modern compilers.
Note: the solution to a similar question unfortunately doesn’t work here.
#include <iostream>
#include <vector>
#include <algorithm>
#include <utility>
#include <functional>
#include <type_traits>
struct X {};
struct Y {};
__int8 f(X x) { return 0; }
__int16 f(...) { return 0; }
template <typename T> typename std::enable_if<sizeof(f(T())) == sizeof(__int8), int>::type call(T const& t) {
std::cout << "In call with f available";
f(t);
return 0;
}
template <typename T> typename std::enable_if<sizeof(f(T())) == sizeof(__int16), int>::type call(T const& t) {
std::cout << "In call without f available";
return 0;
}
int main() {
Y y; X x;
call(y);
call(x);
}
A quick modification of the return types of f() yields the traditional SFINAE solution.
If boost is allowed, the following code might meet your purpose:
#include <boost/type_traits.hpp>
#include <boost/utility/enable_if.hpp>
using namespace boost;
// user code
struct A {};
static void f( A const& ) {}
struct B {};
// code for has_f
static void f(...); // this function has to be a free standing one
template< class T >
struct has_f {
template< class U >
static char deduce( U(&)( T const& ) );
template< class U, class V >
static typename disable_if_c< is_same< V, T >::value, char(&)[2] >::type
deduce( U(&)( V const& ) );
static char (&deduce( ... ))[2];
static bool const value = (1 == sizeof deduce( f ));
};
int main()
{
cout<< has_f<A>::value <<endl;
cout<< has_f<B>::value <<endl;
}
However, there are severe restrictions.
The code assumes that all the user functions have the signature ( T const& ),
so ( T ) isn't allowed.
The function void f(...) in the above seems to need to be a free standing
function.
If the compiler enforces two phase look-up as expected normally, probably
all the user functions have to appear before the definition of has_f class
template.
Honestly, I'm not confident of the usefulness of the code, but anyway I hope
this helps.