first.hpp
#ifndef __HEADER_FIRST_HPP__
#define __HEADER_FIRST_HPP__
#include <type_traits>
template <typename T> typename std::enable_if<std::is_arithmetic<T>::value, int>::type func(const T& x)
{ return x; }
#endif //__HEADER_FIRST_HPP__
second.hpp
#ifndef __HEADER_SECOND_HPP__
#define __HEADER_SECOND_HPP__
#include "first.hpp"
class mytype { mytype( ) = default; };
template <> typename std::enable_if<true, int>::type func(const mytype& x)
{ return 0; }
#endif //__HEADER_SECOND_HPP__
main.cpp
#include <iostream>
#include "second.hpp"
int main(int, char**)
{
std::cout << func(1.0) << std::endl;
std::cout << func(mytype( )) << std::endl;
return 0;
}
In file included from main.cpp:2:0:
second.hpp:8:54: error: template-id 'func<mytype>' for 'std::enable_if<true, int>::type func(const mytype&)' does not match any template declaration
main.cpp: In function 'int main(int, char**)':
main.cpp:7:29: error: no matching function for call to 'func(mytype)'
main.cpp:7:29: note: candidate is:
In file included from second.hpp:4:0,
from main.cpp:2:
first.hpp:6:88: note: template<class T> typename std::enable_if<std::is_arithmetic<_Tp>::value, int>::type func(const T&)
first.hpp:6:88: note: template argument deduction/substitution failed:
first.hpp: In substitution of 'template<class T> typename std::enable_if<std::is_arithmetic<_Tp>::value, int>::type func(const T&) [with T = mytype]':
main.cpp:7:29: required from here
first.hpp:6:88: error: no type named 'type' in 'struct std::enable_if<false, int>'
This code compiles in GCC 4.6. I don't have 4.7 to test with.
#include <type_traits> // firstsomething.hpp template <typename T> typename std::enable_if<std::is_arithmetic<T>::value, T>::type func(const T& x) noexcept { return x; } // something.hpp typedef int mytype; template <> typename std::enable_if<true, mytype>::type func(const mytype& x) noexcept { return 0; } int main() { func(0.0); func(0); }
I actually had the implementation of the specialization in a seperate .cpp file, perhaps this is my error. I'll give it a go
You could try changing the specialization to:
template <> typename std::enable_if<std::is_arithmetic<mytype>::value, mytype>::type func(const mytype& x) noexcept;
I could try this but it would involve specializing is_arithmetic for mytype which is something I don't really want to do. Even still it would only evaluate to true and produce the same problems.
If that doesn't work, you might not need a function specialization in the first place (I'm not sure what exactly you're trying to do), so you ought to be able to use function overloading:
mytype func(const mytype& x) noexcept;
Yeah, it occurred to me that the specialization may not be necessary in the first place and I could have just created an overload (which is what I have done and it seems to work). I think I was concerned that creating an overload would break func for integer types because mytype does not have an explicit constructor and it still takes a single argument integer value. However this is not the case apparently.
Yes. You can't have a partial function specialization in C++ so all function specializations must start with "template<>" (as far as I know).
I did add 'template <typename T>' to the specializations instead of 'template <>' but doesn't this then mean the functions are no longer specializations of the original?
I'm pretty sure partial specializations are allowed for functions, what I had done was not a partial specialization.
I think I would be more comfortable with a template specialization in the header than an overload because of the potential problem I spoke about above. Lets see if it works