I want to be able to have a template type argument as empty, which case the class just has an empty T, or U, or whatever. I tried to do this defaulting the template argument to a simple lambda:
template <typename U = decltype([]() {})>
On Visual Studio 2019 16.9.3 I don't get the right result when I query the type of U, but by trying to compile on OnlineGDB I found out that this probably shouldn't be compiling anyway because the defaulted argument is defining a new type:
#include <iostream>
template <typename T, typename U = decltype([]() { }) >
struct Planet
{
T T_obj;
[[no_unique_address]] U U_obj;
};
int main()
{
Planet<int, char> planet;
std::cout << "Typename = " << typeid([]() {}).name() << '\n'; // Type here is a lambda, which is correct
std::cout << "Typename of U = " << typeid(planet.U_obj).name() << '\n'; // Type here is int, why?
std::cout << "Typename of U = " << typeid(Planet<int>::U_obj).name() << '\n'; // Type here is int, why?
}
Is this just some sort of bug? If I cannot do 'decltype([] () {})' then I can just define 'struct EmptyType{};' just above the template without a problem.
In C++17, a lambda may not appear in an unevaluated context. This restriction was lifted in C++20, but your compiler might not have implemented this feature yet (even if it already supports [[no_unique_address]], another C++20 feature), so you need to upgrade your compiler. And in any case I would recommend not writing code like this, because it would mean that Planet<int> would not be the same type as Planet<int> (even within the same TU), as a new lambda type will be created every time the default argument is used. void might work better as the default type, and you can give U_obj some private empty class type in the case where U is void.
The correct answer to the question was given by Brian Bi (see above). This post is just a follow-up that started from a comment discussion and was requested by the original poster to be elaborated in more detail and might be helpful to somebody trying achieve the same behaviour. Therefore I decided to post it over here rather than somewhere hidden in the comment. The solutions are not equivalent (e.g. stack vs heap allocation) and partially also have a different interface.
Dummy struct
One possible solution would be to simply pass a dummy struct as a default parameter as follows (Wandbox)
struct DummyStruct {
};
template <typename T, typename U = DummyStruct>
struct Planet {
Planet(T const t, U const u = {})
: t_{t}, u_{u} {
return;
}
T t_;
U u_;
};
Pointer to void
Similarly one could use plain or smart pointers and a default type void. The given constructor will not work with template deduction but you can always write a constructor with smart pointers (Wandbox).
template <typename T, typename U = void>
struct Planet {
// Trick to disable this constructor for type void in order to avoid compilation error
template<typename T1 = T, typename U1 = U,
typename std::enable_if_t<!std::is_same_v<U1,void> && std::is_same_v<U1,U>>* = nullptr>
Planet(T1 const& t, U1 const& u)
: t_{std::make_shared<T>(t)}, u_{std::make_shared<U>(u)} {
return;
}
Planet(T const& t)
: t_{std::make_shared<T>(t)}, u_{nullptr} {
return;
}
std::shared_ptr<T> t_;
std::shared_ptr<U> u_;
};
Variadic templates and tuples
One might as well use variadic templates in combination with tuples and then access them with std::get(...) but the usage might be a bit inconvenient (Wandbox)
template <typename... Ts>
struct Planet {
Planet(Ts const&... t)
: t_{std::make_tuple(t...)} {
return;
}
std::tuple<Ts...> t_;
};
Polymorphic vector
Another possibility in some special cases where the involved containers are derived from a common base class and therefore share a common interface is using a std::vector of smart pointers such as (Wandbox):
struct Parent {
virtual void update() = 0;
};
struct Child: public Parent {
void update() override {
// Do something
return;
}
};
struct Planet {
template <typename... Ts>
Planet(std::shared_ptr<Ts>&... t)
: t_{t...} {
// Static assertion with fold expression
static_assert((std::is_base_of_v<Parent, Ts> && ...), "Template arguments must inherit from 'Parent'.");
return;
}
std::vector<std::shared_ptr<Parent>> t_;
};
Related
I know it's generally a bad idea to rely on SFINAE unless absolutely necessary, but I'm curious about how to do the following anyway.
So let's say I have a function that prints a type to the console (class used for partial specialization since it more closely matches my situation):
template <class Ty>
class print
{
public:
print(Ty line)
{
std::cout << line << std::endl;
}
};
Since this is scaled down code, I'm not sure if it would also work with const types, but (because does not in my specific case) let's say the above function does not work with const types. Correct me if I'm wrong, but I believe this would be how you'd accomplish this with partial template specialization?
template <class Ty>
class print <const Ty>
{
public:
print(const Ty line)
{
std::cout << line << std::endl;
}
};
However, is there a way to use the <type_traits> header to do this? I've come across a question that was specific to char* and const char*, but it seems to be different when generalized. Additionally, that question (and answer) is nearly 7 years old.
I've tried the following code (untested) when trying to adapt the answer from the above question to my own situation, but it seems like there should simply be a better way to accomplish this task. In fact, I'm pretty sure my code won't compile (specifically if Ty is already const)
template <class Ty>
struct print_accept_const :
std::enable_if<std::is_same<Ty, Ty>::value || std::is_same<Ty, const Ty>>
{};
template <class Ty, class = print_accept_const<Ty>>
class print
{
print(Ty line)
{
std::cout << line << std::endl;
}
};
Just for reference, I'm using partial template specialization because I'm specializing this print class for std::vector objects, std::set objects, std::unordered_set objects, etc. If there is a way to do this without SFINAE, then I'd be totally open to that.
Edit 1
As asked in a comment, my exact error happens when I try to specialize for std::unordered_set objects.
template <class ValTy>
class print <std::unordered_set<ValTy>>
{
public:
print(std::unordered_set<int> lines) // 'int' instead of 'ValTy' to activate IntelliSense for errors
{
const auto last = --lines.end();
for (auto& line : lines)
{
// IntelliSense, for the line below when 'ValTy' is
// replaced with 'int', says:
//
// no instance of constructor "print<std::unordered_set<ValTy,
// std::hash<ValTy>, std::equal_to<ValTy>, std::allocator<ValTy>>>
// ::print(std::unordered_set<int, std::hash<int>, ...>)" matches
// the argument list. Argument types are (int).
//
print<ValTy> p(line);
}
}
}
Isn't clear what do you exactly want (enable when T is const or isn't const; if you have a function that print value of some types it's necessary wrap it in a template class? Can't you apply SFINAE directly over the function?) anyway... some useful elements...
(1) starting from C++11 there is std::is_const that you can use to check if a type is constant or not
(2) to make an example, a possible way to enable a specialization only for constant types is the following
template <typename T, typename = void>
struct print;
template <typename T>
struct print<T, typename std::enable_if<std::is_const<T>::value>::type>
{
print (T line)
{ std::cout << line << std::endl; }
};
The specialization can be simplified, starting from C++14, using std::enable_if_t
struct print<T, std::enable_if_t<std::is_const<T>::value>>
and, starting from C++17, also using std::is_const_v
struct print<T, std::enable_if_t<std::is_const_v<T>>>
(3) you can enable/disable directly the constructor, but only making is a template one (or SFINAE can't work)
template <typename T>
struct print
{
template <typename U = T,
typename std::enable_if<std::is_const<U>::value, int>::type = 0>
print (U line)
{ std::cout << line << std::endl; }
// possible alternative do-nothing constructor for not const values
template <typename U = T,
typename std::enable_if<! std::is_const<U>::value, int>::type = 0>
print (U)
{ }
};
Observe that, in this case, the SFINAE tests (std::is_same and std::is_const<U>) are (also) over the template parameter of the constructor, U, not over the template parameter of the class, T. Otherwise SFINAE doesn't works.
The first std::enable_if impose that T and U are the same.
So I've been trying to understand variadic templates a little bit more,
My goal was to receive all types, expand them, and print them..
I was able to do it in for a function(found some examples) but I was not able to do it for a class
Here I am trying to build a 'Master' to hold many 'Slaves', each Slave is supposed to have a Slave_T inherit from him and then know it's type, and print it on c'tor.
But for some reason I am not able to fix the ambigious compilation error.. I was trying to avoid passing any of the type as parameters to the function.. I tried with enable_if or true/false_type convensions but was unable, anyone has any idea?
This is my code:(function expansion included)
Function expansion that works:
template<typename T, typename... Targs>
void Print(T value, Targs... Fargs) // recursive variadic function
{
Print<T>();
Print(Fargs...); // recursive call
}
template<typename T>
void Print(T = NULL)
{
std::cout << typeid(T).name() << endl;
}
Class Expansion that I need help with:
#include <iostream>
#include <vector>
#include <type_traits>
#include <memory>
using namespace std;
struct Slave {
virtual char const* Type() = 0;
};
template<typename T>
struct Slave_T : public Slave{
virtual char const* Type() {
return typeid(T).name();
}
};
template <typename ...T>
struct Master {
Master()
{
MakeSlave<T...>();
cout << "All Slaves:" << endl;
for (auto const& slave : v){
cout << slave ->Type() << endl;
}
}
private:
template<typename T, typename ...Rest>
void MakeSlave()
{
MakeSlave<Rest...>(); MakeSlave<T>();
}
template<typename T>
void MakeSlave() {
v.push_back(new Slave_T<T>());
}
vector<shared_ptr<Slave>> v;
};
int main()
{
Master<int, double, char> m;
//Print("Hello", '!', 123, 123);
return 0;
}
Thanks!
Alon
First of all: To allow polymorphic templates, you have defined a non-templated pure-virtual base class Slave. Your template class Slave_T must inherit from it (You want a std::vector containing heterogeneous templates, right?). And note that you are using the virtual function defined by the base class Slave. I think you have forgotten to write the base class list before struct Slave_T :)
Second: In that override of the virtual function Type(), you have written Slave<T>::type instead of Slave_T<T>::type. Also note that this sentence needs typename keyword before it, because is a reference to a dependent scope.. But, on the other hand, you have access to the Slave_T template param T, so, why you don't simply use T? :)
Third: Prefer to use std::make_shared instead of a raw new sentences.
Fourth: Prefer std::string instead of C-style raw-strings.
Edit after code fixes:
Template param T of private function MakeSlave() shadows the class variadic template param T. You must have to use other name.
By the way, the error is that in the overloads of makeslave are ambiguous: You have defined a version with template params T and variadic Params, that is, the tipicall HEAD TAIL recursive approach used with variadic packs. But, on the other hand, you also define a version with only one template param. Note that this make ambiguity with the first version, because a variadic pack can be empty, so in your base case the compiler donesn't know what version use.
Solution:
You could use a sentinel type to track when the param list is completely processed. You use this sentinel to enable/disable the base case to avoid the ambiguity:
template <typename ...T>
struct Master {
Master()
{
MakeSlave<T...,_my_centinel_type>();
cout << "All Slaves:" << endl;
for (auto const& slave : v){
cout << slave ->Type() << endl;
}
}
private:
struct _my_centinel_type {};
template<typename U, typename ...Rest>
typename std::enable_if<!std::is_same<U,_my_centinel_type>::value , void>::type MakeSlave()
{
v.push_back( std::make_shared<Slave_T<U>>());
MakeSlave<Rest...>();
}
template<typename U>
typename std::enable_if<std::is_same<U,_my_centinel_type>::value , void>::type MakeSlave(){
//The base case does anything
}
See it in action: http://ideone.com/FqMPXh#
I have a templated matrix class that I explicitly instantiate for various POD types and custom class types. Some of the member functions however don't make sense for a few of such custom types. For example:
Matrix<int> LoadFile(....); // This makes sense
Matrix<My_custom_class> LoadFile(...); //This doesn't make sense in the context of the custom class
Can I prevent the instantiation of the LoadFile function (which is a member function) for Matrix objects of select types? So far I have avoided the issue by making LoadFile a friend function and then explicitly controlling its instantiation. But I want to know if I can do this when LoadFile is a member function of Matrix.
The first question is whether you really need to control this. What happens if they call that member function on a matrix that stores My_custom_class? Can you provide support in your class (or the template) so that the member function will work?
If you really want to inhibit the use of those member functions for some particular type, then you can use specialization to block the particular instantiation:
template <typename T>
struct test {
void foo() {}
};
template <>
inline void test<int>::foo() = delete;
Or even just add static_asserts to the common implementation verifying the preconditions for what types is it allowed or disallowed?
template <typename T>
struct test {
void foo() {
static_assert(std::is_same<T,int>::value || std::is_same<T,double>::value,
"Only allowed for int and double");
// regular code
}
};
with std::enable_if, this is the best I can come up with
template< typename T >
struct Matrix {
template< typename T >
Matrix< typename std::enable_if<std::is_integral<T>::value, T>::type >
LoadFile()
{
return Matrix<T>();
}
};
Matrix<int> a;
Matrix<int> b = a.LoadFile<int>()
only type int compile while other don't.
Can I prevent the instantiation of the LoadFile function (which is a member function) for Matrix objects of select types?
Your best bet here would be to use a static_assert that would create a compiler error when you attempt to call the method in a version of the class instantiated with a blocked type. Using std::enable_if, and other methods that would selectively "disable" a method itself would require you to create partial or full specializations of the class with and without the methods in question in order to prevent compiler errors. For instance, AFAIK, you cannot do the following:
template <typename T>
struct test
{
static const bool value = false;
};
template<>
struct test<double>
{
static const bool value = true;
};
template<typename T>
struct example
{
void print() { cout << "Printing value from print()" << endl; }
typename enable_if<test<T>::value, T>::type another_print()
{
cout << "Printing value from another_print()" << endl;
return T();
}
};
If you attempted to instantiate an example<int>, etc., you would end up with a compiler error at the point of instantiation of the object type. You couldn't simply call example<int>::print() and be okay, and only run into a problem if you chose to call example<int>::another_print(). Specializations of example<T> could get you around the issue, but that can be a bit of a mess. As originally surmised, a static_assert would probably be the easiest case to handle, along with a nice message to the end-user explaining what went wrong.
Keep in mind that creating compiler errors is the goal, and it's a good one to have. If you blocked a method from being instantiated, and the end-user decided to invoke it, you'd end up with a compiler error either way. The version without the static_assert will leave a lot of head-scratching as the user of your class attempts to parse a probably very verbose compiler error message, where-as the static_assert method is direct and to the point.
If the selected set of types is known at compile time, and you are using c++11 with a compiler that supports type aliases, uniform initialization and constexpr (for example gcc 4.7) you can make your code a bit cleaner like this (from previous example above by yngum):
template <bool Cond, class T = void>
using enable_if_t = typename std::enable_if<Cond, T>::type;
template< typename T >
struct Matrix {
template< typename T >
//std::is_integral has constexpr operator value_type() in c++11. This will work thanks to uniform init + constexpr. With the alias, no more need for typename + ::type
Matrix<enable_if_t<std::is_integral<T>{}>>
LoadFile()
{
return Matrix<T>();
}
};
Matrix<int> a;
Matrix<int> b = a.LoadFile<int>();
Beware of compatibility of this code, though, because these features have been only recently supported and some compilers don't do yet. You can see more about c++11 compiler support here.
If you could use the TypeLists from the ( http://www.amazon.com/Modern-Design-Generic-Programming-Patterns/dp/0201704315 ) - Loki you could implement something like:
template<bool>
struct Static_Assert;
template<>
struct Static_Assert<true>{};
class B{};
template<typename T>
class A{
public:
A(){
Static_Assert< 0 == utils::HasType<T, TYPELIST_2(B,int) >::value >();
}
};
Then your HasType would be something like:
template<typename T, typename TList>
struct HasType{
enum { value = 0+HasType< T, typename TList::Tail >::value };
};
template<typename T>
struct HasType< T, NullType >{
enum { value = 0 };
};
template<typename T, typename U>
struct HasType< T, TypeList<T, U> >{
enum { value = 1 };
};
In the list you can add the classes which you would like prevent to be passed as the template parameters.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Is it possible to emulate template<auto X>?
Consider the following working code:
#include <iostream>
template<typename T> struct Traits {};
template<typename T, typename A>
struct Traits<void(T::*)(A)>
{
typedef T Class;
typedef A Arg;
};
template<typename T, typename U, void(T::*MemFun)(U)>
void Builder()
{
std::cout << typeid(T).name() << std::endl;
std::cout << typeid(U).name() << std::endl;
std::cout << typeid(MemFun).name() << std::endl;
}
template<typename T, T arg>
void Builder()
{
return Builder<Traits<T>::Class,Traits<T>::Arg,arg>();
}
class Class
{
public:
void foo(int) { }
};
int main()
{
Builder<decltype(&Class::foo), &Class::foo>();
}
What I'd like to be able to do is something like this to get the same result, without using a macro.
int main()
{
Builder<&Class::foo>();
}
I can't seem to create a template that takes the pointer to member and deduces the type. Any thoughts? The pointer to member must be used as a template argument as opposed to a function parameter because it's used to create a template function (not shown).
Cannot be done. To have a non-type template argument you must provide the type. So either you limit your Builder to only one particular type or else you need an extra argument (first in the list) that is the type of second argument. Now, if you are willing not to use the member pointer as a constexpr... that is simple.
template <typename T, typename M>
struct Builder {
M T::*ptr;
Builder( M T::*ptr ) : ptr(ptr) {}
};
template <typename T, typename M>
Builder<T,M> createBuilder( M T::*ptr ) {
return Builder<T,M>(ptr);
}
int main() {
auto bld = createBuilder( &Class::member );
}
I have spent some time trying to do a similar thing myself.
I don't think it is possible without using the name of the function Class::foo twice. My reasoning is as follows:
to get the type of foo we must either use decltype or give foo as an argument to a template function
in any of the above, the constexpr-ness of foo (allowing it to be used as a template argument) is lost
moreover, we cannot "duplicate" foo inside a template class or function, as it would face the same problem as above
conclusion: we have to type foo twice at the outer scope
It seems one cannot get away without "dirty" macro tricks, even in C++11...
Unfortunately there's no way to do type deduction for the type of non-type template parameters. A macro is really the only option here.
I have an SFINAE problem:
In the following code, I want the C++ compiler to pick the specialized functor and print "special", but it's printing "general" instead.
#include <iostream>
#include <vector>
template<class T, class V = void>
struct Functor {
void operator()() const {
std::cerr << "general" << std::endl;
}
};
template<class T>
struct Functor<T, typename T::Vec> {
void operator()() const {
std::cerr << "special" << std::endl;
}
};
struct Foo {
typedef std::vector<int> Vec;
};
int main() {
Functor<Foo> ac;
ac();
}
How can I fix it so that the specialized struct is used automatically? Note I don't want to directly specialize the Functor struct on Foo, but I want to specialize it on all types that have a Vec type.
P.S.: I am using g++ 4.4.4
Sorry for misleading you in the last answer, I thought for a moment that it would be simpler. So I will try to provide a complete solution here. The general approach to solve this type of problems is to write a traits helper template and use it together with enable_if (either C++11, boost or manual implementation) to decide a class specialization:
Trait
A simple approach, not necessarily the best, but simple to write would be:
template <typename T>
struct has_nested_Vec {
typedef char yes;
typedef char (&no)[2];
template <typename U>
static yes test( typename U::Vec* p );
template <typename U>
static no test( ... );
static const bool value = sizeof( test<T>(0) ) == sizeof(yes);
};
The approach is simple, provide two template functions, that return types of different sizes. One of which takes the nested Vec type and the other takes ellipsis. For all those types that have a nested Vec the first overload is a better match (ellipsis is the worst match for any type). For those types that don't have a nested Vec SFINAE will discard that overload and the only option left will be the ellipsis. So now we have a trait to ask whether any type has a nested Vec type.
Enable if
You can use this from any library, or you can roll your own, it is quite simple:
template <bool state, typename T = void>
struct enable_if {};
template <typename T>
struct enable_if<true,T> {
typedef T type;
};
When the first argument is false, the base template is the only option, and that does not have a nested type, if the condition is true, then enable_if has a nested type that we can use with SFINAE.
Implementation
Now we need to provide the template and the specialization that will use SFINAE for only those types with a nested Vec:
template<class T, class V = void>
struct Functor {
void operator()() const {
std::cerr << "general" << std::endl;
}
};
template<class T>
struct Functor<T, typename enable_if<has_nested_Vec<T>::value>::type > {
void operator()() const {
std::cerr << "special" << std::endl;
}
};
Whenever we instantiate Functor with a type, the compiler will try to use the specialization, which will in turn instantiate has_nested_Vec and obtain a truth value, passed to enable_if. For those types for which the value is false, enable_if does not have a nested type type, so the specialization will be discarded in SFINAE and the base template will be used.
Your particular case
In your particular case, where it seems that you don't really need to specialize the whole type but just the operator, you can mix the three elements into a single one: a Functor that dispatches to one of two internal templated functions based on the presence of Vec, removing the need for enable_if and the traits class:
template <typename T>
class Functor {
template <typename U>
void op_impl( typename U::Vec* p ) const {
std::cout << "specialized";
}
template <typename U>
void op_impl( ... ) const {
std::cout << "general";
}
public:
void operator()() const {
op_impl<T>(0);
}
};
Even though this is an old question, I think it's still worth providing a couple more alternatives for quickly fixing the original code.
Basically, the problem is not with the use of SFINAE (that part is fine, actually), but with the matching of the default parameter in the primary template (void) to the argument supplied in the partial specialization(typename T::Vec). Because of the default parameter in the primary template, Functor<Foo> actually means Functor<Foo, void>. When the compiler tries to instantiate that using the specialization, it tries to match the two arguments with the ones in the specialization and fails, as void cannot be substituted for std::vector<int>. It then falls back to instantiating using the primary template.
So, the quickest fix, which assumes all your Vecs are std::vector<int>s, is to replace the line
template<class T, class V = void>
with this
template<class T, class E = std::vector<int>>
The specialization will now be used, because the arguments will match. Simple, but too limiting. Clearly, we need to better control the type of the argument in the specialization, in order to make it match something that we can specify as the default parameter in the primary template. One quick solution that doesn't require defining new traits is this:
#include <iostream>
#include <vector>
#include <type_traits>
template<class T, class E = std::true_type>
struct Functor {
void operator()() const {
std::cerr << "general" << std::endl;
}
};
template<class T>
struct Functor<T, typename std::is_reference<typename T::Vec&>::type> {
void operator()() const {
std::cerr << "special" << std::endl;
}
};
struct Foo {
typedef std::vector<int> Vec;
};
int main() {
Functor<Foo> ac;
ac();
}
This will work for any Vec type that could make sense here, including fundamental types and arrays, for example, and references or pointers to them.
Another alternative for detecting the existence of a member type is to use void_t. As valid partial specialisations are preferable to the general implementation as long as they match the default parameter(s), we want a type that evaluates to void when valid, and is only valid when the specified member exists; this type is commonly (and, as of C++17, canonically) known as void_t.
template<class...>
using void_t = void;
If your compiler doesn't properly support it (in early C++14 compilers, unused parameters in alias templates weren't guaranteed to ensure SFINAE, breaking the above void_t), a workaround is available.
template<typename... Ts> struct make_void { typedef void type; };
template<typename... Ts> using void_t = typename make_void<Ts...>::type;
As of C++17, void_t is available in the utilities library, in type_traits.
#include <iostream>
#include <vector>
#include <type_traits> // For void_t.
template<class T, class V = void>
struct Functor {
void operator()() const {
std::cerr << "general" << std::endl;
}
};
// Use void_t here.
template<class T>
struct Functor<T, std::void_t<typename T::Vec>> {
void operator()() const {
std::cerr << "special" << std::endl;
}
};
struct Foo {
typedef std::vector<int> Vec;
};
int main() {
Functor<Foo> ac;
ac();
}
With this, the output is special, as intended.
In this case, since we're checking for the existence of a member type, the process is very simple; it can be done without expression SFINAE or the type_traits library, allowing us to rewrite the check to use C++03 facilities if necessary.
// void_t:
// Place above Functor's definition.
template<typename T> struct void_t { typedef void type; };
// ...
template<class T>
struct Functor<T, typename void_t<typename T::Vec>::type> {
void operator()() const {
std::cerr << "special" << std::endl;
}
};
To my knowledge, this should work on most, if not all, SFINAE-capable C++03-, C++11-, C++14-, or C++1z-compliant compilers. This can be useful when dealing with compilers that lag behind the standard a bit, or when compiling for platforms that don't have C++11-compatible compilers yet.
For more information on void_t, see cppreference.