Template Specialization of Template method - c++

OK I have:
template<typename T>
class Reader
{
class Input
{
template<typename C>
void operator()(C& val) const
{
/* Do Some Work */
}
};
};
Unfortunately the generic version of "Do Some Work" does not work for me. Nor it is easy to modify because it is in the middle of some heavy template meta programming code.
So I though I could specialize the method for my type. So my first step was to try and pull the general method out of the class.
template<typename T>
class Reader
{
class Input
{
template<typename C>
void operator()(C& val) const;
};
};
template<typename T>
template<typename C>
void typename Reader<T>::Input template operator()<C>(C& val) const // LINE 13
{
/* Do Some Work */
}
Unfortunately I am getting the error:
s.h:13: error: error: expected ‘)’ before ‘&’ token

Just write it like normal
template<typename T>
template<typename C>
void Reader<T>::Input::operator()(C& val) const // LINE 13
{
/* Do Some Work */
}
Defining the generic version out of class doesn't help you with providing special versions of it though, or I do miss the goal of yours here.

I guess it is impossible as it counts as partial function template specialization, which is not allowed. void Reader<T>::Input::operator () (C& int) has an implicit first argument (the this pointer) of type Reader<T>::Input *, hence its signature is in fact void (Reader<T>::Input *, C &). You are trying to specify C, yet not T.

Related

passing lambda to void specified template fails

i simplified the problem as much as i could so here is the function in question:
class Test
{
public:
template<class T>
void ExecuteFunction(std::function<void(T)> f)
{
}
};
if i call the function with int-typing everything works fine, however, if i call it with a void-typed lambda it doesn't compile anymore.
Test test;
test.ExecuteFunction<void>( // doesn't compile
[](void)->void
{
int i = 5;
});
test.ExecuteFunction<int>( // this compiles
[](int)->void
{
int i = 5;
});
Compiler errors:
Error C2672 'Test::ExecuteFunction': no matching overloaded function found
Error C2770 invalid explicit template argument(s) for 'void Test::ExecuteFunction(std::function<void(P)>)'
Error (active) no instance of function template "Test::ExecuteFunction" matches the argument list
is there a way around this? how would someone specify the template so that both calls work?
Sure, void in parentheses is but a vintage C-style sugar. You'll have to specialize your template:
template<> void Test::ExecuteFunction<void>(std::function<void()> f) {}
If that does not compile, well, you can use a helper template to encapsulate the type-selection:
#include <iostream>
#include <functional>
template<class T> struct callable {
using type = std::function<void(T)>;
};
template<class T> using callable_t =
typename callable<T>::type;
template<> struct callable<void> {
using type = std::function<void()>;
};
class Test
{
public:
template<class T>
void ExecuteFunction(callable_t<T> f) {}
};
int main() {
Test test;
test.ExecuteFunction<void>( // does compile
[](void)->void {});
test.ExecuteFunction<int>( // this compiles
[](int)->void {});
}
But be aware that this way you'll have to also do something to the arguments passing (in your example, a generic case's argument is unary yet specialization for void expects a nullary function object).
You can add an overload to the class like this:
// as before:
template<class T>
void ExecuteFunction(std::function<void(T)> f) {}
// new overload (not a template):
void ExecuteFunction(std::function<void()> f) {}
As you can't use type deduction anyhow, you can now explicitly call this function by not specifying any template parameter as follows.
Test test;
test.ExecuteFunction(
[](void)->void
{
int i = 5;
});
Is too late to play?
I propose another solution based on a custom type trait (with a specialization for void) that, given a T type, define the correct std::function type; i mean
template <typename T>
struct getFuncType
{ using type = std::function<void(T)>; };
template <>
struct getFuncType<void>
{ using type = std::function<void()>; };
This way your ExecuteFunction() simply become
template <typename T>
void ExecuteFunction (typename getFuncType<T>::type f)
{
}
If you want simplify a little the use of getFuncType, you can add a using helper to extract the type
template <typename T>
using getFuncType_t = typename getFuncType<T>::type;
so the ExecuteFunction() can be simplified as follows
template <typename T>
void ExecuteFunction (getFuncType_t<T> f)
{
}

avoid pointer-to-member-function for non-class type

I am writing a kind of container class, for which I would like to offer an apply method which evaluates a function on the content of the container.
template<typename T>
struct Foo
{
T val;
/** apply a free function */
template<typename U> Foo<U> apply(U(*fun)(const T&))
{
return Foo<U>(fun(val));
}
/** apply a member function */
template<typename U> Foo<U> apply(U (T::*fun)() const)
{
return Foo<U>((val.*fun)());
}
};
struct Bar{};
template class Foo<Bar>; // this compiles
//template class Foo<int>; // this produces an error
The last line yields error: creating pointer to member function of non-class type ‘const int’. Even though I only instantiated Foo and not used apply at all. So my question is: How can I effectively remove the second overload whenever T is a non-class type?
Note: I also tried having only one overload taking a std::function<U(const T&)>. This kinda works, because both function-pointers and member-function-pointers can be converted to std::function, but this approach effectively disables template deduction for U which makes user-code less readable.
Using std::invoke instead helps, it is much easier to implement and read
template<typename T>
struct Foo
{
T val;
template<typename U> auto apply(U&& fun)
{
return Foo<std::invoke_result_t<U, T>>{std::invoke(std::forward<U>(fun), val)};
}
};
struct Bar{};
template class Foo<Bar>;
template class Foo<int>;
However, this won't compile if the functions are overloaded
int f();
double f(const Bar&);
Foo<Bar>{}.apply(f); // Doesn't compile
The way around that is to use functors instead
Foo<Bar>{}.apply([](auto&& bar) -> decltype(auto) { return f(decltype(bar)(bar)); });
Which also makes it more consistent with member function calls
Foo<Bar>{}.apply([](auto&& bar) -> decltype(auto) { return decltype(bar)(bar).f(); });
In order to remove the second overload you'd need to make it a template and let SFINAE work, e. g. like this:
template<typename T>
struct Foo
{
T val;
//...
/** apply a member function */
template<typename U, typename ObjT>
Foo<U> apply(U (ObjT::*fun)() const)
{
return Foo<U>((val.*fun)());
}
};
Alternatively, you could remove the second overload altogether, and use lambda or std::bind:
#include <functional> // for std::bind
template<typename T>
struct Foo
{
T val;
/** apply a member function */
template<typename U, typename FuncT>
Foo<U> apply(FuncT&& f)
{
return {f(val)};
}
};
struct SomeType
{
int getFive() { return 5; }
};
int main()
{
Foo<SomeType> obj;
obj.apply<int>(std::bind(&SomeType::getFive, std::placeholders::_1));
obj.apply<int>([](SomeType& obj) { return obj.getFive(); });
}
How can I effectively remove the second overload whenever T is a non-class type?
If you can use at least C++11 (and if you tried std::function I suppose you can use it), you can use SFINAE with std::enable_if
template <typename U, typename V>
typename std::enable_if<std::is_class<V>{}
&& std::is_same<V, T>{}, Foo<U>>::type
apply(U (V::*fun)() const)
{ return Foo<U>((val.*fun)()); }
to impose that T is a class.
Observe that you can't check directly T, that is a template parameter of the class, but you have to pass through a V type, a template type of the specific method.
But you can also impose that T and V are the same type (&& std::is_same<V, T>{}).

how to use enable_if with overloads

enum class enabler{};
template<typename T>
class X {
template<typename std::enable_if<std::is_class<T>::value,enabler>::type = enabler()>
void func();
void func(int a);
void func(std::string b);
};
I have this class with these 3 overloads for func. I need the second/third versions to be available for both class/non-class types, and the first version to be available only for class types. when I tried to use enable_if as above, the class instantiation for non-class types gives compile error.
For SFINAE to work, the template argument must be deduced. In your case, T is already known by the time you attempt to instantiate func, so if the enable_if condition is false, instead of SFINAE, you get a hard error.
To fix the error, just add a template parameter whose default value is T, and use this new parameter in the enable_if check. Now deduction occurs and SFINAE can kick in for non-class types.
template<typename U = T,
typename std::enable_if<std::is_class<U>::value,enabler>::type = enabler()>
void func();
And you don't really need a dedicated enabler type either, this works too
template<typename U = T,
typename std::enable_if<std::is_class<U>::value, int>::type* = nullptr>
void func();
I'm not really sure what you're going for with enabler here, but you can't do what you're trying because the declaration for your member function must be valid since T is not deduced by func. To achieve what you want in adding an extra overload, you can use some moderately contrived inheritance.
struct XBaseImpl {
// whatever you want in both versions
void func(int a) { }
void func(std::string b) { }
};
template <typename, bool> struct XBase;
// is_class is true, contains the extra overload you want
template <typename T>
struct XBase<T, true> : XBaseImpl {
static_assert(std::is_class<T>{}, ""); // just to be safe
using XBaseImpl::func;
void func() { } // class-only
};
// is_class is false
template <typename T>
struct XBase<T, false> : XBaseImpl { };
template<typename T>
class X : public XBase<T, std::is_class<T>{}> { };
You are not enabling or disabling something.
You simply want a compile time error in one specific case.
Because of that you don't require to rely on sfinae, a static_assert is enough.
As a minimal, working example:
#include<string>
template<typename T>
class X {
public:
void func() {
static_assert(std::is_class<T>::value, "!");
// do whatever you want here
}
void func(int a) {}
void func(std::string b) {}
};
int main() {
X<int> x1;
X<std::string> x2;
x2.func(42);
x2.func();
x1.func(42);
// compilation error
// x1.func();
}
Once a SO user said me: this is not sfinae, this is - substitution failure is always an error - and in this case you should use a static_assert instead.
He was right, as shown in the above example a static_assert is easier to write and to understand than sfinae and does its work as well.

Specialize a Template Function to Generate a Compile-Time Error

How does one specialize a template function to generate an error at compile-time if a user attempts to call said function with a given template parameter?
I was able to get this behavior for a template class by using the following idiom...
template <typename T>
class MyClass< std::vector<T> >;
The basic signature of the function which I am trying to modify is...
template <typename T>
T bar(const int arg) const {
...
}
If I use the same paradigm that I used to disallow certain template classes...
template<>
std::string foo::bar(const int arg) const;
I can generate a linker error, which I suppose is more desirable than a runtime error, but still not really what I'm looking for.
Since I am not able to use C++11, I cannot use static_assert, as described here. Instead, I am trying to use BOOST_STATIC_ASSERT like so...
template<>
std::string foo::bar(const int arg) const {
BOOST_STATIC_ASSERT(false);
return "";
}
However, this generates the following compile-time error, even when I am not trying to call an instance of the function with the template parameter I am attempting to disallow...
error: invalid application of 'sizeof' to incomplete type 'boost::STATIC_ASSERTION_FAILURE<false>'
I found this post, but it doesn't really offer any insight that I feel applies to me. Can anyone help?
Use boost::is_same to generate a compile-time boolean value that can then be used with BOOST_STATIC_ASSERT to perform the check.
template <typename T>
T bar(const int)
{
BOOST_STATIC_ASSERT_MSG((!boost::is_same<T, std::string>::value),
"T cannot be std::string");
return T();
}
bar<int>(10);
bar<std::string>(10); // fails static assertion
Live demo
It seems C++ don't allow specialize template member function. So if you want to use same interface, you should use other technology. I'd like to use trait_type to implement this.
template <class T>
struct is_string : false_type {};
template <>
struct is_string<string> : true_type {};
template <typename T>
class MyClass {
private:
T bar(const int arg, false_type) const {
return T();
}
std::string bar(const int arg, true_type) const {
return "123";
}
public:
T bar(const int arg) const {
return bar(arg, is_string<T>());
}
};
If you can not use C++11, you must implement false_type and true_type yourself. Or you can use specialize template class.

function specialization based on if template parameter is shared_ptr

I'm trying to detect if a type is a shared_ptr<T> and if it is, dispatch to a specific function template or override.
Here's a simplified version of what I'm actually attempting:
#include <type_traits>
#include <memory>
#include <cstdio>
template <class T> struct is_shared_ptr : std::false_type {};
template <class T> struct is_shared_ptr<std::shared_ptr<T> > : std::true_type {};
class Foo { };
typedef std::shared_ptr<Foo> SharedFoo;
template<class T> void getValue();
template<class T, typename std::enable_if<is_shared_ptr<T>::value>::type = 0>
void getValue()
{
printf("shared!\n");
}
template<class T, typename std::enable_if<!is_shared_ptr<T>::value>::type = 0>
void getValue()
{
printf("not shared!\n");
}
int main(int, char **)
{
getValue<SharedFoo>();
getValue<Foo>();
return 0;
}
It compiles just fine, but it seems the actual functions were never actually generated because the code doesn't link with the following errors:
/tmp/ccjAKSBE.o: In function `main':
shared_test.cpp:(.text+0x10): undefined reference to `void getValue<std::shared_ptr<Foo>>()'
shared_test.cpp:(.text+0x15): undefined reference to `void getValue<Foo>()'
collect2: error: ld returned 1 exit status
I would think that those would be covered by the two function templates. But they aren't.
Given that, it seems I am seriously misunderstanding something.
So maybe it would help if I explain what I'm /trying/ to do rather than what I'm actually doing.
I have some "magic" code using a bunch of new (to me) C++11 features to bind C++ code to lua (can be seen here: https://github.com/Tomasu/LuaGlue). someone has recently asked for support for binding to classes wrapped in shared_ptr's. which is not something that works at the moment, because it binds at compile time using templates and tuple unwrapping to generate code to call functions on either the C++ or lua side. In the "magic" unwrapping code, I have a bunch of overridden and "specialized" functions that handle various variable types. Some for basic types, one for static objects, and another for pointer to objects. A shared_ptr can't be handled in the same way as either a static or pointer object, so I need to add some extra handling just for them.
For example:
template<typename T>
T getValue(LuaGlue &, lua_State *, unsigned int);
template<>
int getValue<int>(LuaGlue &, lua_State *state, unsigned int idx)
{
return luaL_checkint(state, idx);
}
template<class T>
T getValue(LuaGlue &g, lua_State *state, unsigned int idx)
{
return getValue_<T>(g, state, idx, std::is_pointer<T>());
}
That's the actual code (notice the hairy template/override via function argument :-x).
I had thought it'd be as simple as adding another addValue function, along the lines of the code in my earlier example, via enable_if.
Any reason not to simply use partial specialization?
#include <type_traits>
#include <memory>
#include <cstdio>
class Foo { };
typedef std::shared_ptr<Foo> SharedFoo;
template <class T>
struct getValue {
getValue() {
printf("not shared!\n");
}
};
template <class T>
struct getValue<std::shared_ptr<T> > {
getValue() {
printf("shared!\n");
}
};
int main(int, char **)
{
getValue<SharedFoo>();
getValue<Foo>();
return 0;
}
Your program declares template<class T> void getValue() but doesn't define it. template <typename, typename> void getValue() is a different function. The compiler is picking template<class T> void getValue() as a better match with your invocations, which of course fails at link time as there is no definition of that function.
I prefer the simplicity of tag dispatch when it's applicable (live at Coliru):
template<class T>
void getValue(std::true_type)
{
printf("shared!\n");
}
template<class T>
void getValue(std::false_type)
{
printf("not shared!\n");
}
template<class T>
void getValue() {
return getValue<T>(is_shared_ptr<T>{});
}
Here is another solution which is basically a fix for the OP rather than alternatives (using a class and its constructor as in zennehoy's post or tag dispatch as in Casey's).
// Do not provide this declaration:
// template<class T> void getValue();
template<class T>
typename std::enable_if<is_shared_ptr<T>::value>::type
getValue()
{
printf("shared!\n");
}
template<class T>
typename std::enable_if<!is_shared_ptr<T>::value>::type
getValue()
{
printf("not shared!\n");
}
I must say that, as Casey has put it, I also "prefer the simplicity of tag dispatch". Hence, I would go for his solution.
I also found zennehoy's idea interesting but, unfortunately, it doesn't allow your function to return something. (I believe a workaround is possible but it adds complexity.) With the solution here you just need to provide the return type as the 2nd parameter of std::enable_if.