I am pretty new to std::variant and C++17 feature. I know that variant can store multiple types, but maybe it would not allow the user defined template class.
I was wondering if I could use the following.
template<typename T>
class A
{
public:
A(){}
A(T value) : _value(value){}
public:
T _value;
};
using variant_t = std::variant<A<std::string>, A<int>, A<bool>, A<double>, A<unsigned int>, A<unsigned short>>;
int main()
{
std::unordered_map<std::string, variant_t> Foo;
Foo = {{"name", A("name")}};
return 0;
}
I am not sure how I am getting a syntax error, and it's saying that compiler cannot deduce template argument for std::unordered_map. But if i use the using variant_t = std::variant<A<std::string>, A<int>, A<bool>, A<double>, A<unsigned int>, A<unsigned short>>; inside of main. the syntax errors have gone. Than, there is errors in xhash saying that unary '++': '_Iter' does not define this operator or a conversion to a type acceptable to the predefined operator and binary !=: _iter does not define this operator of a conversion to a type acceptable to the predefined operator.
Does this mean that I would have to initialize one of the types while using the variant?
Foo = {{"name", A("name")}};
This would deduce the A instance to A<const char*>, not A<std::string>.
If you want to use the assignment operator taking an initializer list, you'll have to help it to get the contained types right:
Foo = {std::pair<const std::string, variant_t>{"name", variant_t("name")}};
or simply
Foo = {{"name", variant_t("name")}};
or even
Foo = {{"name", A<std::string>("name")}};
Another option is to add a deduction guide for A:
A(const char*) -> A<std::string>;
That deduction guide will then let you use your original form:
Foo = {{"name", A("name")}};
Related
I have a template class with a constructor in which I want to explicitly forbid the usage of any type beyond a well defined list, like this:
template<typename Anything>
class MyClass
{
public:
MyClass(int &);
MyClass(float &);
MyClass(Anything &) = delete;
}
However, since the code for the integer and the double version are identical, and only differ in the type, I'd like to define it using the templatized version, such as:
template<typename Anything>
MyClass<Anything>::MyClass(Anything &var)
{
/* Code that operates over var */
...
}
instead of virtually having to duplicate the code for both valid constructors.
However, when I tried to do so, I get:
error: redefinition of 'MyClass<Anything>::MyClass(Anything&)'
It works by removing the "= delete".
Is there a way to use the template to define the function but without explicitly allowing to receive more types than the ones also explicitly described?
I checked How can I prevent implicit conversions in a function template? and also Why can I prevent implicit conversions for primitives but not user-defined types?, but their issues don't seem to be equivalent to the current one.
Thanks a lot.
UPDATE: Using gcc-4.8.5, it works!!! Even with the = delete keyword included.
The problem with your definition is that you're trying to implement the exact function that you have marked with = delete.
You actually want another function template that works with both int and float. You can achieve that by first defining an IntOrFloat predicate:
template <typename T>
using IntOrFloat = std::bool_constant<
std::is_same_v<T, int> || std::is_same_v<T, float>>;
Then you can define two unambiguous constructors that use std::enable_if_t to check whether or not the predicate is fulfilled by the type passed in by the user:
class MyClass
{
public:
template <typename T,
std::enable_if_t<IntOrFloat<T>{}>* = nullptr>
MyClass(T&);
template <typename Anything,
std::enable_if_t<!IntOrFloat<Anything>{}>* = nullptr>
MyClass(Anything&) = delete;
};
Usage example:
int main()
{
int v0 = 0;
float v1 = 0.f;
const char* v2 = "igijsdg";
MyClass x0{v0}; // OK
MyClass x1{v1}; // OK
MyClass x2{v2}; // Error
}
live example on wandbox
Unfortunately, the only tutorial that I have found about concepts was the concept lite tutorial (and it was really basic). And even with the technical specification, there is some signatures function that I don't know how translate into concepts (maybe just because my English is bad and I can't read the technical specification really well).
So there is a list of signatures function I still don't know how to "translate":
CFoo --> class CFoo {};
void Foo1() const;
CFoo& Foo2();
void Foo3(CFoo&);
{static, friend, ... } void Foo4();
template < typename ... Args >
void Foo5(Args && ... args);
I want to have some kind of interface for a class with these functions.
Don't even know if it's possible at this point. Foo2 and Foo3 seems to be the same problem.
Honestly I really want to know Foo2 and Foo5.
I tried somethings, for the Foo2 but I don't have any idea about Foo5:
class Handle {};
template < typename Object >
concept bool C_Object =
requires(Handle handle) {
{get(handle)} -> Object&
};
template < C_Object Object >
class Foo {
Object obj;
};
int main() {
Foo<int> test;
return 0;
}
I know this won't compile because Foo don't have a get menber, but these are not the right errors:
Test1.cpp:6:16: error: there are no arguments to ‘get’ that depend on a template parameter, so a declaration of ‘get’ must be available [-fpermissive]
{get(handle)} -> Object&
^
Test1.cpp:6:16: note: (if you use ‘-fpermissive’, G++ will accept your code, but allowing the use of an undeclared name is deprecated)
Test1.cpp: In function ‘int main()’:
Test1.cpp:18:10: error: template constraint failure
Foo<int> test;
^
Test1.cpp:18:10: note: constraints not satisfied
Test1.cpp:4:14: note: within ‘template<class Object> concept const bool C_Object<Object> [with Object = int]’
concept bool C_Object =
^~~~~~~~
Test1.cpp:4:14: note: with ‘Handle handle’
Test1.cpp:4:14: note: the required expression ‘get(handle)’ would be ill-formed
If someone can point me out some resources or, why not, a solution. It will be great.
Have a great day
I know this won't compile because Foo don't have a get menber […]
Concepts deal with normal expressions. In particular, the scope of requires expressions is normal scope, not class scope. This may be more apparent with this concept:
template<typename Lhs, typename Rhs>
concept bool Addable = requires(Lhs lhs, Rhs rhs) {
lhs + rhs;
};
Addable<int, long> is fulfilled because given int lhs; long rhs; then lhs + rhs is a valid expression. We're using the built-in addition operator on two (pretend) variables we explicitly introduced in the parameter list, not calling a member operator+ on an implicit *this.
Concepts are about interfaces in the wider sense (as in 'API'), not in a narrower OOP sense. You can think of Addable as a relation on pairs of types. That Addable<int, long> holds doesn't mean int on its own has a special relationship with Addable. It is true that Addable can be used as e.g.
template<Addable<long> Var>
struct client {
Var var;
};
and then client<int> comes with an Addable<int, long> constraint, but this shortcut is syntactical in nature. It's a helpful way of cutting down boilerplate, namely sparing us from writing template<typename Var> requires Addable<Var, long>.
With that in mind, here are some expressions that may come close to checking the member signatures you mentioned, plus the Handle scenario:
template<typename Obj>
concept bool Object = requires(Obj obj, Obj const cobj, Handle handle) {
cobj.Foo1();
{ obj.Foo2() } -> Obj&;
obj.Foo3(obj);
// static
Obj::Foo4();
// non-member, possibly friend
Foo4(obj);
{ obj.get(handle) } -> Obj&;
};
(I elided the Foo5 scenario because it's worth its own question, here is a lead.)
I want a class that can be initialized from any sequence, that means from any type that has methods begin() and end() returning iterators.
template<typename B>
class A
{
public:
A(any_sequence_type<B> arglist)
{
for(B b : arglist)
init_members(b);
}
}
I want the following to compile:
A<int> a = {1, 2, 3};
A<int> b = std::vector<int>();
A<Something> c = MyClassWithBeginAndEnd();
Is it possible?
EDIT:
Suggested solutions with template constructor don't work.
GCC says: template argument deduction/substitution failed: couldn't deduce template parameter ‘T’.
Clang says: candidate template ignored: couldn't infer template argument 'T'.
If I explicitly cast the initializer, things start to work, though.
A a = A({B(), B(), B()}); // does not work
A a = (std::initializer_list<B>){B(), B(), B()}; // works
Why is that?
With template constructor:
template<typename B>
class A
{
public:
template <typename T>
A(T&& arglist)
{
for (auto&& b : arglist) {
init_members(b);
}
}
// overload for initializer_list
A(std::initializer_list<B> arglist) {
for (auto&& b : arglist) {
init_members(b);
}
}
};
You got error if T doesn't provide begin/end and if content is not convertible to B.
You may use SFINAE to restrict allowed type T and so having error to call site instead of inside your constructor in case of misuse.
Demo
You need a template parameter for the type that A::A accepts. You should use SFINAE to disable this constructor if Seq is not a suitable sequence type; otherwise you will have issues with it winning overload resolution over the copy constructor.
template <typename Seq,
typename = std::enable_if_t<
std::is_convertible<decltype(*std::declval<Seq>().begin()), B>::value &&
std::is_convertible<decltype(*std::declval<Seq>().end()), B>::value>>
A(Seq arglist) {
for (B b : arglist) {
init_members(b);
}
}
Also consider using const Seq& instead of Seq, and const B& b or auto&& b instead of B b, to avoid potentially expensive copies.
If you want it to work with a braced-init-list too, you must add a separate std::initializer_list constructor. This is because a braced-init-list is not an expression and does not have a type; it is essentially always a special case.
I define a template class in which, I define two type-cast operator
template <class base_t>
struct subclass {
base_t base;
//any function which defined for 'base_t' can be used with 'subclass<base_t>'
operator base_t&() {
return base;
}
//I want 'subclass<base_t>' can be converted to any class which 'base_t' can
//I want this operator is called only if 'target_t' is not 'base_t'
template <class target_t>
operator target_t&() {
return (target_t)base;
}
};
The class looks fine, but there're a problem when I try to convert subclass<int> to int. For instance:
typedef subclass<int> foo_t;
foo_t foo = {1234};
cout << foo << endl; //Error here: ambiguous; This line is compiled only if I delete 'template<class target_t> operator target_t&()'
Please tell me how
EDIT
Everything work fine if I don't define the template. However, if I define a subclass< subclass<int> >, I can convert it to subclass<int> but I can't convert it to int
typedef subclass<int> level1;
typedef subclass<level1> level2;
level1 a = {1234};
level2 b = {a};
cout << a << endl;
cout << b << endl; //Error! Because the compiler doesn't provide a type-cast from level2 to int
What you're trying to do makes little sense.
We have subclass<int>. It is convertible to int&, but also to a lot of other reference types. char&. bool&. double&. The ambiguity arises from the fact that all the various overloads for operator<< that take any non-template argument are viable overload candidates with equivalent conversion sequences. And for good measure, you probably don't want to do any of those conversions anyway.
What you want is just the base& operator:
template <class base_t>
struct subclass {
base_t base;
operator base_t&();
};
That's really all you need. This gives you the reference implicitly to the type you're storing, and you can already take base-class references to it too:
subclass<Derived> obj;
Base& base = obj; // totally OK with just that one operator
I don't see what problem the template operator T& solves.
However, when I define, subclass < subclass<int> > and it can converted to subclass<int> but can't be converted to int
First of all, subclass<subclass<int>> can be converted to subclass<int>&, not subclass<int>. That said, if we want that to work, we can add a conversion operator specifically for that case. First, add a type trait to find what the most nested type is:
template <class base_t>
struct subclass;
template <typename T>
struct nested { using type = T; };
template <typename T>
struct nested<subclass<T>> : nested<T> { };
And then define a template operator conversion for the nested case:
template <typename T,
typename = std::enable_if_t<std::is_same<T, typename nested<base_t>::type>::value>>
operator T&() {
return base;
}
We make it a template so that there isn't an ambiguous overload in the case where we're just one subclass deep. And with that, both of these work:
subclass<subclass<subclass<int>>> s{{{4}}};
int& i = s;
subclass<int> s2{5};
int& i2 = s2;
You can use a bit of SFINAE techniques to make this work
template <class target_t, class = std::enable_if< !std::is_same<target_t, base_t>::value && std::is_convertible<base_t, target_t>::value> >
operator target_t&() {
return (target_t)base;
}
Not the best syntax in the world, but that's how C++ currently works until Concepts Lite are standardized
I have a Visual Studio 2008 C++ project with a template class that takes the templated value in the constructor like this:
template< typename A >
struct Foo
{
const A& a_;
Foo( const A& a ) : a_( a ) { };
};
Therefore, I have to construct this class like this:
int myval = 0;
Foo< int > foo( myval );
It seems redundant to have to specify int as a template parameter when it's already specified in the constructor. I'd like some way to use it like this:
Foo foo( myval );
As is, I get the compiler error:
error C2955: 'Foo' : use of class template requires template argument list
Thanks,
PaulH
C++17 fixed this issue, introducing template argument deduction for constructors.
Citing Herb Sutter:
[...] you can write just pair p(2, 4.5); instead of pair<int,double> p(2, 4.5); or auto p = make_pair(2, 4.5);. This is pretty sweet, including that it obsoletes many “make” helpers.
If you name the type at all, it has to be the complete type (i.e., Foo<int> and not just Foo).
A class can have multiple constructors or may have no constructors that have a parameter of the class template's type parameter, so there's no way to make this work for all class templates (in my opinion it would be confusing to have this work sometimes but not all the time).
If you are okay not naming the type at all, you can write a MakeFoo<T>() function template that constructs a Foo<T> and use function template argument deduction:
template <typename A>
Foo<A> MakeFoo(const A& a) { return Foo<A>(a); }
This pattern is commonly used in C++ (see, for example, make_shared).
If you want to store the returned object in a variable, though, that variable still needs to have a type. If you are able to move to a compiler that supports C++0x's auto (like Visual C++ 2010), then you can use that. Otherwise, you can use a third-party solution like BOOST_AUTO or write your own (though that would likely be quite a lot of work (-: ).
With auto, your code would look like:
auto foo(MakeFoo(myval));
Type deduction happens only with function template argument, not with class template argument.
In C++0x, you can do something like this:
template<typename T>
Foo<T> CreateFoo(const T & a)
{
return Foo<T>(a);
}
auto foo = CreateFoo(myval); //No need to write CreateFoo<int>(myval);