Disable default template and only use specialization through sfinae - c++

Consider the following system:
template<typename T>
struct wrapper
{
operator T * () { return nullptr; }
};
template<typename Ret, typename T>
Ret func(T);
template<>
int func(float * in)
{
std::cout << "long";
}
template<>
long func(float * in)
{
std::cout << "int";
}
The purpose of the wrapper is to allow it to decay to the type it is templated to (it is a wrapper around a buffer of the type). Moreover, i have a set of functions that are templated specializations of a template. This is to circumvent the usual error when overloading based on only the return type.
This doesn't work though, as noted here:
// the following should work, but doesn't because it's instantiating
// the func<ret, wrapper<float>> which doesn't exist resulting in a linker error
// instead of selecting the int func(float *) overload
wrapper<float> w;
func<int>(w);
Conversely, i would like this to generate a compile-time error (but again, it's generating a link-time error):
// the following should generate a compile-time error
// since no explicit overload for int func(int *) exists
wrapper<int> w2;
func<int>(w2);
So ideally, i would like to disable the original template (maybe through sfinae if this is possible?) such that the overload resolution only considers the explicit specializations, and generates a compile-time error if no match is found. Can this be done?
A portable solution between clang and msvc is a must, but I'm using the newest versions of both.

Another approach may be to use static_assert:
template<typename Ret, typename T>
Ret func(T) {
static_assert(false, "template specialization required");
}

If you do
template<typename Ret> Ret func(float*);
it works as expected: Live example

While Jarod's answer solved one of the problems, i still needed a way to overload the function arguments (which in that case would generate 'no matching template' errors) - i probably didn't state that in the OP.
It dawned on me, that the parameter type(s) are always dependant on the return type. I could then construct a helper-struct, that would do the sfinae:
template<typename T>
struct option_of;
template<>
struct option_of<int>
{
typedef float value;
};
template<>
struct option_of<long>
{
typedef double value;
};
and then the default template would look like this:
template<typename Ret>
Ret func(typename const option_of<Ret>::value *);
and the overloads could then be constructed like this:
template<>
int func(const float * in)
{
std::cout << "long";
}
template<>
long func(const double * in)
{
std::cout << "int";
}
-without problems. Note that any other combination of returns and parameter types would be invalid (since they are not a specialization of the original template, which only considers the options i give it). This also reduces the only overload resolutions to the two overloads, and thus makes this possible:
wrapper<float> w;
func<int>(w); // works
func<long>(w); // invalid, because no combination of long and float exists according to option_of
wrapper<int> w2; // works, but
func<int>(w2); // invalid because option_of doesn't consider int's
The added bonus of course is the compiler recognizes the error at the call / instantiation with a correct error message, instead of some random static_assert / linker errors. Success!

Related

How do I add a template specialization when for a generic method on a generic class when the two types are equal?

I'm trying to add in a specialization where the generic type of method and class agree, but I haven't been able to figure out exactly how to specify the template instantiation (if it is even possible).
My best guess would be something like the following (though it obviously doesn't compile):
template<typename ClassT>
class Foo
{
public:
ClassT x;
template<typename MethodT>
void Bar(MethodT arg)
{
}
};
template<typename T>
template<>
void Foo<T>::Bar(T arg)
{
x = arg;
}
As is usually the case when considering function template specialization, an overload can handle it:
template<typename MethodT>
void Bar(MethodT arg)
{
}
void Bar(ClassT arg)
{
x = arg;
}
When you call Bar, one of the candidates will be a function template specialization and one won't. Think of the class template as stamping out real, concrete member functions where possible when it's instantiated. There's a rule pretty late in overload resolution to prefer the one that isn't a function template specialization if it's a tie up to that point.
What you end up with is the second overload being called when there's an "exact match" in types (which allows for a difference in top-level const). If exact matches are too narrow, you can restrict the first overload to widen the second:
// Allow the other overload to win in cases like Foo<int>{}.Bar(0.0).
// std::enable_if works as well before C++20.
template<typename MethodT>
void Bar(MethodT arg) requires (not std::convertible_to<MethodT, ClassT>)
{
}
As discussed in the comments, it's not possible to do this with template specialization. However, something similar can be accomplished by using std::enable_if_t and
template<typename ClassT>
class Foo
{
public:
ClassT x;
template<typename MethodT,
typename = std::enable_if_t<!std::is_same<ClassT, MethodT>::value>>
void Bar(MethodT arg)
{
}
void Bar(ClassT arg)
{
x = arg;
}
};
std::enable_if_t will only return a valid type when the input type arg is true. Therefore, the template substitution will fail when MethodT and ClassT are the same type, but the non-template overload will not fail. The template substitution failure is ok under SFINAE.

decltype throwing errors on template methods that aren't generating code

I'm trying to create a sort of wrapper class that forwards all operators to its contained object, to try and make it able to "pretend" to be the contained object. The code I'd like to write looks something like this (simplified):
template<typename T>
class Wrapper
{
private:
T val;
public:
Wrapper(T value) : val(value) {}
auto operator++() -> decltype(++this->val)
{
return ++this->val;
}
};
This works fine with an int, but if I try to pass a std::string into it, I get the error cannot increment value of type 'std::basic_string<char>'.
I also tried using declval here, but that only made things worse, as not only did it still throw errors on std::string, it also threw them on int in that case due to int not being a class.
Now, in normal situations, this function wouldn't be generated at all because I'm not calling it. But, for whatever reason, the decltype is still being processed on this function even though it isn't being generated at all. (If I remove the decltype and change the return type to void, I can compile with std::string with no problem.)
So my question is: is there any way I can get around this? Maybe some crazy trick using SFINAE? Or, is it possible this is improper behavior for the compiler in the first place, since the function isn't generating code?
EDIT: Solution, modified somewhat from the solution suggested by BЈовић:
//Class, supports operator++, get its declared return type
template<typename R, bool IsObj = boost::is_class<R>::value, bool hasOp = boost::has_pre_increment<R>::value> struct OpRet
{
typedef decltype(++std::declval<R>()) Ret;
};
//Not a class, but supports operator++, return type is R (i.e., ++int returns int)
template<typename R> struct OpRet<R, false, true>
{
typedef R Ret;
};
//Doesn't support operator++, return type is void
template<typename R> struct OpRet<R, true, false>
{
typedef void Ret;
};
template<typename R> struct OpRet<R, false, false>
{
typedef void Ret;
};
template<typename T>
class Wrapper
{
private:
T val;
public:
Wrapper(T value) : val(value) {}
auto operator++() -> typename OpRet<T>::Ret
{
return ++val;
}
};
This will work with both simple and class types, and for class types, will also work in situations where the return type of operator++ is not R (which is probably very rare for operator++, but worth taking into account for the sake of maximum compatibility.)
is there any way I can get around this?
You can use boost::has_pre_increment and SFINAE :
#include <string>
#include <boost/type_traits.hpp>
template<typename R,bool hasOp = boost::has_pre_increment<R>::value > struct OpRet
{
typedef R Ret;
};
template<typename R> struct OpRet<R,false>
{
typedef void Ret;
};
template<typename T>
class Wrapper
{
private:
T val;
public:
Wrapper(T value) : val(value) {}
auto operator++() -> typename OpRet<T>::Ret
{
return ++val;
}
};
int main()
{
Wrapper<std::string> a("abc");
Wrapper<int> b(2);
}
is it possible this is improper behavior for the compiler in the first place, since the function isn't generating code?
No. The compiler issues proper diagnostic. The std::string really has no prefix increment operator. [temp.deduct] 7 and 8 are clear about this :
7:
The substitution occurs in all types and expressions that are used in the function type and in template parameter declarations. The expressions include not only constant expressions such as those that appear in array bounds or as nontype template arguments but also general expressions (i.e., non-constant expressions) inside sizeof, decltype, and other contexts that allow non-constant expressions. [ Note: The equivalent substitution in exception specifications is done only when the function is instantiated, at which point a program is ill-formed if the substitution results in an invalid type or expression. — end note ]
8:
If a substitution results in an invalid type or expression, type deduction fails. ...
You indeed want SFINAE. operator++ needs to be made a function template for that, and a good trick is to use a default argument for the template parameter to turn T into a dependent type (this is necessary for SFINAE to apply).
template<typename U = T>
auto operator++() -> decltype(++std::declval<U&>())
{
return ++this->val;
}
As you may notice however, we lose the convenience of using the member directly, and we need a bit of thinking to figure out what exactly we should feed to std::declval to get the value category and cv-qualifiers right.

Semi-generic function

I have a bunch of overloaded functions that operate on certain data types such as int, double and strings. Most of these functions perform the same action, where only a specific set of data types are allowed. That means I cannot create a simple generic template function as I lose type safety (and potentially incurring a run-time problem for validation within the function).
Is it possible to create a "semi-generic compile time type safe function"? If so, how? If not, is this something that will come up in C++0x?
An (non-valid) idea;
template <typename T, restrict: int, std::string >
void foo(T bar);
...
foo((int)0); // OK
foo((std::string)"foobar"); // OK
foo((double)0.0); // Compile Error
Note: I realize I could create a class that has overloaded constructors and assignment operators and pass a variable of that class instead to the function.
Use sfinae
template<typename> struct restrict { };
template<> struct restrict<string> { typedef void type; };
template<> struct restrict<int> { typedef void type; };
template <typename T>
typename restrict<T>::type foo(T bar);
That foo will only be able to accept string or int for T. No hard compile time error occurs if you call foo(0.f), but rather if there is another function that accepts the argument, that one is taken instead.
You may create a "private" templatized function that is never exposed to the outside, and call it from your "safe" overloads.
By the way, usually there's the problem with exposing directly the templatized version: if the passed type isn't ok for it, a compilation error will be issued (unless you know your algorithm may expose subtle bugs with some data types).
You could probably work with templates specializations for the "restricted" types you want to allow. For all other types, you don't provide a template specialization so the generic "basic" template would be used. There you could use something like BOOST_STATIC_ASSERT to throw a compile error.
Here some pseudo-code to clarify my idea:
template <typename T>
void foo(T bar) {BOOST_STATIC_ASSERT(FALSE);}
template<> // specialized for double
void foo(double bar) {do_something_useful(bar);};
Perhaps a bit ugly solution, but functors could be an option:
class foo {
void operator()(double); // disable double type
public:
template<typename T>
void operator ()(T bar) {
// do something
}
};
void test() {
foo()(3); // compiles
foo()(2.3); // error
}
Edit: I inversed my solution
class foo {
template<typename T>
void operator ()(T bar, void* dummy) {
// do something
}
public:
// `int` is allowed
void operator ()(int i) {
operator ()(i, 0);
}
};
foo()(2.3); // unfortunately, compiles
foo()(3); // compiles
foo()("hi"); // error
To list an arbitrary selection of types I suppose you could use a typelist. E.g see the last part of my earlier answer.
The usage might be something like:
//TODO: enhance typelist declarations to hide the recursiveness
typedef t_list<std::string, t_list<int> > good_for_foo;
template <class T>
typename boost::enable_if<in_type_list<T, good_for_foo> >::type foo(T t);

How to call a templated function if it exists, and something else otherwise?

I want to do something like
template <typename T>
void foo(const T& t) {
IF bar(t) would compile
bar(t);
ELSE
baz(t);
}
I thought that something using enable_if would do the job here, splitting up foo into two pieces, but I can't seem to work out the details. What's the simplest way of achieving this?
There are two lookups that are done for the name bar. One is the unqualified lookup at the definition context of foo. The other is argument dependent lookup at each instantiation context (but the result of the lookup at each instantiation context is not allowed to change behavior between two different instantiation contexts).
To get the desired behavior, you could go and define a fallback function in a fallback namespace that returns some unique type
namespace fallback {
// sizeof > 1
struct flag { char c[2]; };
flag bar(...);
}
The bar function will be called if nothing else matches because the ellipsis has worst conversion cost. Now, include that candidates into your function by a using directive of fallback, so that fallback::bar is included as candidate into the call to bar.
Now, to see whether a call to bar resolves to your function, you will call it, and check whether the return type is flag. The return type of an otherwise chosen function could be void, so you have to do some comma operator tricks to get around that.
namespace fallback {
int operator,(flag, flag);
// map everything else to void
template<typename T>
void operator,(flag, T const&);
// sizeof 1
char operator,(int, flag);
}
If our function was selected then the comma operator invocation will return a reference to int. If not or if the selected function returned void, then the invocation returns void in turn. Then the next invocation with flag as second argument will return a type that has sizeof 1 if our fallback was selected, and a sizeof greater 1 (the built-in comma operator will be used because void is in the mix) if something else was selected.
We compare the sizeof and delegate to a struct.
template<bool>
struct foo_impl;
/* bar available */
template<>
struct foo_impl<true> {
template<typename T>
static void foo(T const &t) {
bar(t);
}
};
/* bar not available */
template<>
struct foo_impl<false> {
template<typename T>
static void foo(T const&) {
std::cout << "not available, calling baz...";
}
};
template <typename T>
void foo(const T& t) {
using namespace fallback;
foo_impl<sizeof (fallback::flag(), bar(t), fallback::flag()) != 1>
::foo(t);
}
This solution is ambiguous if the existing function has an ellipsis too. But that seems to be rather unlikely. Test using the fallback:
struct C { };
int main() {
// => "not available, calling baz..."
foo(C());
}
And if a candidate is found using argument dependent lookup
struct C { };
void bar(C) {
std::cout << "called!";
}
int main() {
// => "called!"
foo(C());
}
To test unqualified lookup at definition context, let's define the following function above foo_impl and foo (put the foo_impl template above foo, so they have both the same definition context)
void bar(double d) {
std::cout << "bar(double) called!";
}
// ... foo template ...
int main() {
// => "bar(double) called!"
foo(12);
}
litb has given you a very good answer. However, I wonder whether, given more context, we couldn't come up with something that's less generic, but also less, um, elaborate?
For example, what types can be T? Anything? A few types? A very restricted set which you have control over? Some classes you design in conjunction with the function foo? Given the latter, you could simple put something like
typedef boolean<true> has_bar_func;
into the types and then switch to different foo overloads based on that:
template <typename T>
void foo_impl(const T& t, boolean<true> /*has_bar_func*/);
template <typename T>
void foo_impl(const T& t, boolean<false> /*has_bar_func*/);
template <typename T>
void foo(const T& t) {
foo_impl( t, typename T::has_bar_func() );
}
Also, can the bar/baz function have just about any signature, is there a somewhat restricted set, or is there just one valid signature? If the latter, litb's (excellent) fallback idea, in conjunction with a meta-function employing sizeof might be a bit simpler. But this I haven't explored, so it's just a thought.
I think litb's solution works, but is overly complex. The reason is that he's introducing a function fallback::bar(...) which acts as a "function of last resort", and then goes to great lengths NOT to call it. Why? It seems we have a perfect behavior for it:
namespace fallback {
template<typename T>
inline void bar(T const& t, ...)
{
baz(t);
}
}
template<typename T>
void foo(T const& t)
{
using namespace fallback;
bar(t);
}
But as I indicated in a comment to litb's original post, there are many reasons why bar(t) could fail to compile, and I'm not certain this solution handles the same cases. It certainly will fail on a private bar::bar(T t)
If you're willing to limit yourself to Visual C++, you can use the __if_exists and __if_not_exists statements.
Handy in a pinch, but platform specific.
EDIT: I spoke too soon! litb's answer shows how this can actually be done (at the possible cost of your sanity... :-P)
Unfortunately I think the general case of checking "would this compile" is out of reach of function template argument deduction + SFINAE, which is the usual trick for this stuff. I think the best you can do is to create a "backup" function template:
template <typename T>
void bar(T t) { // "Backup" bar() template
baz(t);
}
And then change foo() to simply:
template <typename T>
void foo(const T& t) {
bar(t);
}
This will work for most cases. Because the bar() template's parameter type is T, it will be deemed "less specialised" when compared with any other function or function template named bar() and will therefore cede priority to that pre-existing function or function template during overload resolution. Except that:
If the pre-existing bar() is itself a function template taking a template parameter of type T, an ambiguity will arise because neither template is more specialised than the other, and the compiler will complain.
Implicit conversions also won't work, and will lead to hard-to-diagnose problems: Suppose there is a pre-existing bar(long) but foo(123) is called. In this case, the compiler will quietly choose to instantiate the "backup" bar() template with T = int instead of performing the int->long promotion, even though the latter would have compiled and worked fine!
In short: there's no easy, complete solution, and I'm pretty sure there's not even a tricky-as-hell, complete solution. :(
//default
//////////////////////////////////////////
template <class T>
void foo(const T& t){
baz(t);
}
//specializations
//////////////////////////////////////////
template <>
void foo(const specialization_1& t){
bar(t);
}
....
template <>
void foo(const specialization_n& t){
bar(t);
}
Are you not able to use full specialisation here (or overloading) on foo. By say having the function template call bar but for certain types fully specialise it to call baz?

GCC Template issue

Visual Studio compiles this code fine, but gcc only lets it compile without the Template operator. With the Template operator it gives the following errors:
Line 29: error: expected `;' before "itrValue"
class Test
{
public:
Test& operator<<(const char* s) {return *this;} // not implemented yet
Test& operator<<(size_t s) {return *this;} // not implemented yet
Test& operator<< (const std::list<const char*>& strList)
{
*this << "count=" << strList.size() << "(";
for (std::list<const char*>::const_iterator itrValue = strList.begin();
itrValue != strList.end(); ++itrValue)
{
*this << " " << *itrValue;
}
*this << ")";
return *this;
}
template <class T>
Test& operator<< (const std::list<T>& listTemplate)
{
*this << "count=" << listTemplate.size() << "(";
// this is line 28, the next line is the offending line
for (std::list<T>::const_iterator itrValue = listTemplate.begin();
itrValue != listTemplate.end(); ++itrValue)
{
*this << " " << *itrValue;
}
*this << ")";
return *this;
}
};
GCC is right, const_iterator is a type, and template dependant in the template operator<<, you need to tell the compiler it's a type and not a variable:
typename std::list<T>::const_iterator
To complete #Pieter answer, which is correct, some more info on how templates are processed.
First of all, templates are only compiled whenever they are instantiated, so that if you do not instantiate the template for a given type then the code will never be compiled.
Now, when you do instantiate a template, there is a two steps validation of the template code. First the template is verified for correctness regardless of what the instantiation type is. To check with a simpler to understand example:
#include "a.h"
template <typename T> void f( T const & )
{
T::type x; // is T::type a type?
};
int main()
{
A a;
f( a );
}
During the first phase, the template is checked for syntax correctness without considering what A really is. At this time the syntax A::type could be a type by the name of 'type' or it could be a static variable by the same name.
struct A { // version 1
typedef int type;
};
struct A { // version 2
static std::string type;
};
std::string A::type = "A";
In the first case, type is indeed a type, in the second it is not. Now the standard states that if it is really a type then the programmer of the template must state so to inform the compiler with the syntax above:
template <typename T> void f( T const & a )
{
typename T::type x; // define a variable x of type T::type
}
Now, to complete the processing, the compiler must check that the template code is not only correct in itself, but that when it is instantiated with the particular type T it is also correct. This is what the compiler performs during the second stage of validation. It applies the type and rechecks for errors.
In your case, it is a little more controversial, as everyone (but the compiler) knows that std::list::const_iterator is a type for any given T. Well, it does not need to be. From a language standpoint, some code could provide a template specialization for a particular data type T that is different to the general list template. The compiler cannot know whether that could be so.
Note that it would be horribly wrong to specialize a template in the std namespace with something that changes behavior in as much as redefining the iterator types. But the compiler sees std namespace just as any other namespace, and list as any other templated class.
I think it's worth telling you about the other disambiguations. For typename i already answered another one here.
The other one is template. Look here:
template<typename T>
struct some {
template<int V>
struct other {
typedef int type;
static const int value = V;
};
};
template<typename V>
void doit() {
typename some<V>::template other<42>::type * int_pointer;
}
Note how we had to use both template and typename disambiguations. The typename told the compiler
The thing you access called ::type is indeed a type. Don't do multiplication, which would wrongly assume ::type is a static value (integer or something).
The template told the compiler
The other<42> is a template used with the 42 argument. It's not a comparison using operator> and operator< of other with 42 and what follows (which would indeed be total nonsense).