I'm very new to templates and concepts and started using them in Visual Studio 2022 (17.4.2).
Here is a program that compiles, but I find that the IntelliSense it not working as I had hoped:
struct Entity {
int i;
Entity(const int i_) : i(i_) {}
virtual ~Entity() {}
};
struct A : public Entity {
bool a;
A(const int i_, const bool a_) : Entity(i_), a(a_) {}
};
template <class T>
concept hasI = requires(T a) { a.i; };
template <class T>
concept ofEntity = std::derived_from<T, Entity>;
// template <ofEntity T> // doesn't make IntelliSense work either
template <hasI T>
void tfunc(const std::map<int, std::shared_ptr<T>>& m) {
for (auto& it : m) {
// ------------------------ V -------------- No IntelliSense?
std::cout << it.second->i << std::endl;
}
}
static void run() {
std::map<int, std::shared_ptr<Entity>> aMap;
std::shared_ptr<A> myA = std::make_shared<A>(1, true);
aMap.insert({myA->i, myA});
tfunc(aMap);
}
As you can see in the marked line, I access the member, but while typing it, I do not get any suggestions. I understand that this is not working for general templates, but I was hoping that this would work in conjunction with concepts.
Having no IntelliSense in all functions with templates sounds very cumbersome, as errors will only show up when you compile and missing suggestions means slower coding.
From the replies here I expected this to be implemented by now. Is there anything I'm missing or not doing incorrectly?
Thank you in advance!
Related
Suppose I have the following very simple class:
class A
{
public:
static constexpr A make() { return A{}; }
constexpr A() : _v(0) {}
constexpr A& setV(int v) { _v = v; return *this; }
private:
int _v;
};
If I try to use it as follows:
int main()
{
volatile A a1;
a1.setV(10);
//OR
//The optimizer will optimize this chain of constexpr calls into a single "store" instruction
a1 = A::make().setV(10); //More chaining here
return 0;
}
The code will not compile.
I understand why this is true based upon: Defining volatile class object
I know that the solution would be to add an additional method like so:
class A
{
public:
constexpr A() : _v(0) {}
volatile A& setV(int v) volatile { _v = v; return *this; }
constepxr A& setV(int v) { _v = v; return *this; }
private:
int _v;
};
As an aside, I am aware that returning the volatile reference will issue a warning if it is not used.
My question is, is there any way I can avoid code duplication in this case? Both implementations of setV will always be the same. Thus, if I add/change more methods, I have to maintain them both which could get messy if they aren't so trivial. The only difference is one of type qualifiers...
Since there have been some mentions of this in the comments, I thought I would note that I need volatile here because I am attempting to eventually implement "class overlay" for hardware peripheral register access on an embedded system.
In C++23, you can use an explicit object parameter (also known as deducing this) for this purpose:
class A
{
public:
A() : _v(0) {}
template <class Self>
constexpr auto&& setV(this Self&& self, int v) {
self._v = v; return self;
}
private:
int _v;
};
Unfortunately, as of this writing the only compiler that supports this is the latest version of Microsoft Visual C++.
I came up with one possible solution. It's dubious whether it's less verbose than what I had before, but at least I don't have to duplicate the body of the method. In fact, it's similar (in my mind) to the proposed C++23 answer by #ComicSansMS.
class A
{
public:
constexpr A() : _v(0) {}
template <typename T>
static constexpr void setV(T& dest, int src) { dest = src; }
volatile A& setV(int v) volatile { setV(_v, v); return *this; }
constepxr A& setV(int v) { setV(_v, v); return *this; }
private:
int _v;
};
T will be deduced as either int& or volatile int& depending on the context. Since its declare constexpr/inline, the compiler/optimizer still boils it down to a few assembly instructions.
Let's say I'm trying to create a Combine class that will be derived from the given base classes.
template<typename ...Bases>
class Combine : public Bases... {};
And this works fine. For example, if I have class Foo and class Bar then class Combine<Foo, Bar> will implement all the methods from Foo and Bar. At least I thought so until I tried this:
struct ContainerProvider {
std::vector<int> container{1, 2, 3};
};
struct ConstGetter : public virtual ContainerProvider {
[[nodiscard]] const int &get(int index) const {
return container[index];
}
};
struct MutableGetter : public virtual ContainerProvider {
int &get(int index) {
return container[index];
}
};
template<typename ...Bases>
class Combine : public Bases... {};
int main() {
Combine<ConstGetter, MutableGetter> container;
container.get(1); // Member 'get' found in multiple base classes of different types
}
In normal situations, I would just use using Super::method;, but here I don't know the names of derived methods. In a perfect world, I could use something like this:
template<typename ...Bases>
class Combine : public Bases... {
using Bases::* ...;
};
But C++ does not allow this.
Is it possible to implement my Combine class somehow? I'm pretty sure the compiler can get all the information to resolve this edge case, but I have no idea how to provide it to make it work.
Curious problem since get() defined only in one class would work perfectly, but in two? Error? I was curious if there might be a core language defect since this problem seems solvable by the compiler, but I didn't see any (http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html).
The ideal solution would probably be for MutableGetter to inherit from ConstGetter since, logically, a getter that allows mutation should also allow grabbing non-mutable versions.
struct MutableGetter : public ConstGetter {
using ConstGetter::get;
int &get(int index) {
return container[index];
}
};
Here's the closest I could get:
#include <iostream>
#include <vector>
struct ContainerProvider {
std::vector<int> container{1, 2, 3};
};
struct ConstGetter : public virtual ContainerProvider {
[[nodiscard]] const int &get(int index) const {
std::cout << "CONST" << std::endl;
return container[index];
}
};
struct MutableGetter : public virtual ContainerProvider {
int &get(int index) {
std::cout << "NON-CONST" << std::endl;
return container[index];
}
};
template <typename... Bases>
class Combine;
template <typename B1, typename B2, typename... Bases>
struct Combine<B1, B2, Bases...> : public B1, public Combine<B2, Bases...> {
using B1::get;
using Combine<B2, Bases...>::get;
};
template<typename B>
struct Combine<B> : B {
using B::get;
};
int main() {
Combine<ConstGetter, MutableGetter> container;
std::cout << container.get(0) << std::endl; // non-const
const auto &const_container = container;
std::cout << const_container.get(0) << std::endl; // const
}
It really sucks for the Combine to have to know what member functions its parents expose, though. I found one partial solution if you're willing to drop the idea of member functions and occasionally do a cast...: Use friend functions
#include <iostream>
#include <vector>
struct ContainerProvider {
std::vector<int> container{1, 2, 3};
};
class ConstGetter : public virtual ContainerProvider {
[[nodiscard]] const int &get(int index) const {
std::cout << "CONST" << std::endl;
return container[index];
}
friend [[nodiscard]] const int& get(const ConstGetter &self, int i) { return self.get(i); }
};
class MutableGetter : public virtual ContainerProvider {
int &get(int index) {
std::cout << "NON-CONST" << std::endl;
return container[index];
}
friend [[nodiscard]] const int &get(MutableGetter &self, int i) {
return self.get(i);
}
};
template <typename... Bases>
class Combine : public Bases... {};
int main() {
Combine<ConstGetter, MutableGetter> container;
std::cout << get((MutableGetter&)container, 0) << std::endl;
const auto &const_container = container;
std::cout << get(const_container, 0) << std::endl;
}
I imagine that renaming ConstGetter::get() to ConstGetter::const_get is not an option? However, this compiles: container.ConstGetter::get(); container.MutableGetter::get();, check it here
As of why overload resolution doesn't work across classes, you could check
this old post
and the answer of this question.
I'm trying to store and manipulate a list of template class objects with different parameter types; the template class has two parametrised methods, one returning the parameter type and a void one accepting it as input.
More specifically, I have a template class defined as follows:
template<typename T>
class Test
{
public:
virtual T a() = 0;
virtual void b(T t) = 0;
};
And different specifications of it, such as:
class TestInt : public Test<int>
{
public:
int a() {
return 1;
}
void b(int t) {
std::cout << t << std::endl;
}
};
class TestString : public Test<std::string>
{
public:
std::string a() {
return "test";
}
void b(std::string t) {
std::cout << t << std::endl;
}
};
I'd like to be able to store in one single list different objects of both TestInt and TestString type and loop through it calling one method as input for the other, as in:
for (auto it = list.begin(); it != list.end(); ++it)
(*it)->b((*it)->a());
I've looked into boost::any but I'm unable to cast the iterator to the specific class, because I don't know the specific parameter type of each stored object. Maybe this cannot be done in a statically typed language as C++, but I was wondering whether there could be a way around it.
Just for the sake of completeness, I'll add that my overall aim is to develop a "parametrised observer", namely being able to define an observer (as with the Observer Pattern) with different parameters: the Test class is the observer class, while the list of different types of observers that I'm trying to properly define is stored within the subject class, which notifies them all through the two methods a() and b().
The virtuals have actually no meaning here, since for each T the signatures are distinct.
So it seems you have Yet Another version of the eternal "how can we emulate virtual functions templates" or "how to create an interface without virtual functions":
Generating an interface without virtual functions?
How to achieve "virtual template function" in C++
The first one basically contains an idea that you could employ here.
Here's an idea of what I'd do:
Live On Coliru
#include <algorithm>
#include <iostream>
namespace mytypes {
template <typename T>
struct Test {
T a() const;
void b(T t) { std::cout << t << std::endl; }
};
template <> int Test<int>::a() const { return 1; }
template <> std::string Test<std::string>::a() const { return "test"; }
using TestInt = Test<int>;
using TestString = Test<std::string>;
}
#include <boost/variant.hpp>
namespace mytypes {
using Value = boost::variant<int, std::string>;
namespace detail {
struct a_f : boost::static_visitor<Value> {
template <typename T>
Value operator()(Test<T> const& o) const { return o.a(); }
};
struct b_f : boost::static_visitor<> {
template <typename T>
void operator()(Test<T>& o, T const& v) const { o.b(v); }
template <typename T, typename V>
void operator()(Test<T>&, V const&) const {
throw std::runtime_error(std::string("type mismatch: ") + __PRETTY_FUNCTION__);
}
};
}
template <typename O>
Value a(O const& obj) {
return boost::apply_visitor(detail::a_f{}, obj);
}
template <typename O, typename V>
void b(O& obj, V const& v) {
boost::apply_visitor(detail::b_f{}, obj, v);
}
}
#include <vector>
int main()
{
using namespace mytypes;
using AnyTest = boost::variant<TestInt, TestString>;
std::vector<AnyTest> list{TestInt(), TestString(), TestInt(), TestString()};
for (auto it = list.begin(); it != list.end(); ++it)
b(*it, a(*it));
}
This prints
1
test
1
test
Bonus Points
If you insist, you can wrap the AnyTest variant into a proper class and have a() and b(...) member functions on that:
Live On Coliru
int main()
{
using namespace mytypes;
std::vector<AnyTest> list{AnyTest(TestInt()), AnyTest(TestString()), AnyTest(TestInt()), AnyTest(TestString())};
for (auto it = list.begin(); it != list.end(); ++it)
it->b(it->a());
}
Expanding on my comment above, the simplest what I can currently think of to achieve what you are trying to do - at least as I understood it from your example code - is the following:
/* Interface for your container, better not forget the destructor! */
struct Test {
virtual void operate(void) = 0;
virtual ~Test() {}
};
/* Implementation hiding actual type */
template<typename T>
struct TestImpl : public T, public Test {
void operate(void) {
T::b(T::a());
}
};
/* Actual code as template policies */
struct IntTest {
int a(void) {
return 42;
}
void b(int value) {
std::cout << value << std::endl;
}
};
struct StringTest {
std::string a(void) {
return "Life? Don't talk to me about life.";
}
void b(std::string value) {
std::cout << value << std::endl;
}
};
You would then need to create a container for objects of class Test and fill it with objects of the respective TestImpl<IntTest>, TestImpl<StringTest>, and so on. To avoid object slicing you need reference or pointer semantics, that is std::vector<std::unique_ptr<Test> > for example.
for (auto it = list.begin(); it != list.end(); ++it) {
(*it)->operate();
}
I'm trying to write a template function, but I have trouble specializing it for vector<> and another class at the same time. Here is the code I'm using :
// template definition
template< class T >
void f( const T& value)
{
cout << "DEFAULT" << endl;
}
// specialization for MyClass
template< class T >
void f<> ( const MyClass & value )
{
cout << "MyClass" << endl;
}
// specialization for vector
template< class T >
void f<>( const std::vector<T> & v )
{
cout << "vector" << endl;
}
MyClass and MyClass2 are defined as:
class MyClass{
virtual void a() = 0;
};
class MyClass2 : public MyClass{
void a(){}
};
Finally, the main function:
int main(int nArgs, char *vArgs[]){
MyClass2 e;
f<MyClass>(e);
}
Here is the error I get when I try compiling it using Visual Studio 2010:
c:\program files (x86)\microsoft visual studio 10.0\vc\include\vector(869): error C2259: 'MyClass' : cannot instantiate abstract class
This seems to be very specific to this particular situation: As soon as I remove the const modifiers, I change the vector into a list or I make MyClass concrete, everything works. But for my problem I need for this particular situation to work.
Is anybody having the same error as me, and more importantly does anybody know a fix/workaround for this?
I believe this:
// specialization for vector
template< class T >
void f<>( const std::vector<T> & v )
{
cout << "vector" << endl;
}
is not possible (even if your syntax were corrected, as Anton did in his answer), because it is not a full specialization of f (there are unbound type parameters). Partial function specialization is not allowed under the C++ standard.
There are a few other questions on Stack Overflow involving similar code with similar issues. This one (and the winning answer) seems to be quite relevant: Why function template cannot be partially specialized?
You can peruse the C++ standards for yourself, if you were feeling particularly masochistic. You might start from section 14.7.3 ("Explicit specialization") at page 368 of this document: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf (which is a semi-recent draft, but not the most up to date. It is free, however.)
As other answers have indicated:
your syntax for specialization is wrong
you cannot partially specialize a template function
...does anybody know a fix/workaround for this?
Since you are using the template argument in the argument list, you can use overloaded functions.
template <class T>
void f(const T& value)
{
std::cout << "DEFAULT" << std::endl;
}
void f(const MyClass& value)
{
std::cout << "MyClass" << std::endl;
}
template <class T>
void f(const std::vector<T>& v) // this is an overload, not a specialization
{
std::cout << "vector" << std::endl;
}
int main()
{
f(1);
MyClass2 e;
f(e);
f(std::vector<int>());
}
You have mistakes in specialization syntax.
Probably, it should look like this:
// MyClass
class MyClass{
virtual void a() = 0;
};
class MyClass2 : public MyClass{
void a(){}
};
// template definition
template< class T >
void f(const T& value)
{
cout << "DEFAULT" << endl;
};
// specialization for MyClass
template<>
void f(const MyClass & value)
{
cout << "MyClass" << endl;
};
// specialization for vector of MyClass
template<>
void f(const std::vector<MyClass> & v)
{
cout << "vector" << endl;
}
int main()
{
// Using template for any type
f(2);
// Using specialization for MyClass
MyClass2 e;
f<MyClass>(e);
// Using specialization for vector<MyClass>
vector<MyClass> vM;
f(vM);
}
In writing a program, I've come up with a piece of code that I cannot manage to make code-duplication free.
#include <iostream>
using namespace std;
class Presenter{
public:
template <typename T>
void addField(T& t){
cout << "do something that could happen to modify t" << endl;
}
template <typename T>
void addField(const T& t){
cout << "do something that cannot possibly happen to modify t" << endl;
}
};
class Presented{
public:
Presented() : a(0), b(0.) {}
void bind(Presenter& p){
p.addField(a);
p.addField(b);
//...
}
void bind(Presenter& p) const {
p.addField(a);
p.addField(b);
//...
}
private:
int a;
double b;
//...
};
int main() {
Presenter presenter;
Presented p1;
const Presented p2;
p1.bind(presenter);
p2.bind(presenter);
}
Here is a simple dummy program which shows the issue. As you see, the code of the two bind functions is (looks) exactly the same. Of course it is not, since two different functions (addField) are used, which only happen to share the name.
Nonetheless, I have been looking for a way to remove the need to verbatim write the void bind(Presenter& p) const.
Does anyone see a method for reaching the goal? I wasn't able to come up with one.
Delegate to a template that can be called with a const or a non-const instance of Presented:
class Presented{
public:
Presented() : a(0), b(0.) {}
void bind(Presenter& p){
bindImpl(p, *this);
}
void bind(Presenter& p) const {
bindImpl(p, *this);
}
private:
template<typename P>
static void bindImpl(Presenter& p, P& presented)
{
p.addField(presented.a);
p.addField(presented.b);
}
int a;
double b;
};