I have written a custom vector class template and print_vector function template that is supposed to print the content of my custom vector class. The print_vector function uses v.sz and v.elem which are declared private inside the vector class. However I am unable to declare print_vector as a friend inside my vector class. I want to keep the print_vector separately defined in t_vector.cpp.
A problem is that print_vector takes a parameter of the same type as the class it is declared friend in (becomes a circular dependency?). I also get an error saying that print_vector is not declared in scope.
I have marked the problematic places with // <--
// t_vector.h
#ifndef T_VECTOR_H
#define T_VECTOR_H
#include <string>
template <typename T>
void print_vector(Vector<T>& v);
template <typename T>
struct Vector {
private:
int sz;
T* elem;
public:
Vector() = delete;
explicit Vector(int s);
Vector(const Vector<T>& v);
~Vector();
Vector<T>& operator=(const Vector<T>& v);
T& operator[](int e) const;
template<typename U>
friend void print_vector(Vector<U>& v); // <-- TRYING TO FRIEND print_vector
};
#endif
// t_vector.cpp
#include "t_vector.h"
#include <stdexcept>
#include <iostream>
#include <string>
using std::cout;
using std::endl;
using std::string;
template <typename T>
Vector<T>::Vector(int s) {
if (s < 0) throw std::invalid_argument("Negative size");
cout << this << " called Vector(int s) constructor" << endl;
sz = s;
elem = new T[sz];
}
template <typename T>
Vector<T>::Vector(const Vector<T>& v) : sz{v.sz}, elem{new T[v.sz]} {
cout << this << " called Copy constructor on " << &v << endl;
for (int i = 0; i<sz; ++i) {
elem[i] = v[i];
}
}
template <typename T>
Vector<T>::~Vector() {
cout << "~" << this << " delete elem " << &elem << endl;
delete[] elem;
}
template <typename T>
Vector<T>& Vector<T>::operator=(const Vector<T>& v) {
cout << this << " called Copy assignment operator to copy " << &v << endl;
if (this != &v) {
T *tmp = new T[v.sz];
for (int i=0; i<v.sz; ++i ) {
tmp[i] = v.elem[i];
}
sz = v.sz;
delete[] elem;
elem = tmp;
}
return *this;
}
template <typename T>
T& Vector<T>::operator[](int e) const {
if (e < 0 || e >= sz) throw std::out_of_range("Vector::operator[]");
return elem[e];
}
template <typename T>
void print_vector(Vector<T>& v) { // <--- THIS FUNCTION WANTS TO READ v.sz WHICH IS PRIVATE
for (int i = 0; i < v.sz-1; ++i) {
cout << '[' << v.elem[i] << ']';
}
cout << '[' << v[v.sz-1] << ']' << endl;
}
// test_t_vector.cpp
#include "t_vector.h"
#include "t_vector.cpp"
#include <iostream>
using std::cout;
using std::endl;
int main() {
cout << "---------- Starting: test_vector ----------" << endl;
Vector<int> vec(3);
vec[2] = 5;
print_vector(vec);
cout << "---------- Exiting: test_vector ----------" << endl;
return 0;
}
Error output:
g++ -O0 -Wall -Wextra -pedantic-errors -Wold-style-cast -fno-elide-constructors -std=c++14 -g -ggdb3 -MT t_vector.o -MMD -MP -MF t_vector.d -std=c++14 -I. -c -o t_vector.o t_vector.cpp
In file included from t_vector.cpp:1:
t_vector.h:7:6: error: variable or field ‘print_vector’ declared void
7 | void print_vector(Vector<T>& v);
| ^~~~~~~~~~~~
t_vector.h:7:19: error: ‘Vector’ was not declared in this scope
7 | void print_vector(Vector<T>& v);
| ^~~~~~
t_vector.h:7:27: error: expected primary-expression before ‘>’ token
7 | void print_vector(Vector<T>& v);
| ^
t_vector.h:7:30: error: ‘v’ was not declared in this scope
7 | void print_vector(Vector<T>& v);
| ^
make: *** [<builtin>: t_vector.o] Error 1
As Ted Lyngmo and Retired Ninja mentioned the problem is that the implementation should have been visible in the header file. One of the methods to achieve this is to include a .tpp file with all the template implementations in the header file and include this file in the end of the header file. Unfortunately my class template seemed to work despite separating the class template declaration in the header file and the implementation details in a cpp file. This can occur by luck but the general rule is to show implementation details in header one way or another.
Related
Following on from this extracting a template parameter pack with different types into a vector of doubles produces warnings and cigien's answer.
I have the following code:
enum class p_type {p1, p2, p3};
class testerx
{
public:
void process1(double a)
{
std::cout << "1" << a << std::endl;
};
void process2(double a, double b)
{
std::cout << "2" << a << " " << b << std::endl;
};
void process3(double a, double b, double c)
{
std::cout << "3" << a << " " << b << " " << c << std::endl;
};
};
// The template type
template<typename TESTER, typename... ARGS>
class tester_templatex
{
public:
explicit tester_templatex(p_type type) : m_type(type) {};
void process(ARGS... args)
{
// Create a vector to put the args into. use double since that can hold all of the types
// that I am using
size_t param_count = sizeof...(args);
std::cout << "PARAM COUNT X " << param_count << std::endl;
std::vector<double> args_vect = {static_cast<double>(args)...};
for (auto arg : args_vect)
{
std::cout << "arg: " << arg << std::endl;
}
// Now call the tester
std::cout << "running tester: ";
switch (m_type)
{
case p_type::p1:
if constexpr (sizeof...(args) == 1)
m_tester.process1(args...);
break;
case p_type::p2:
if constexpr (sizeof...(args) == 2)
m_tester.process2(args...);
break;
case p_type::p3:
if constexpr (sizeof...(args) == 3)
m_tester.process3(args...);
break;
}
std::cout << std::endl;
};
p_type m_type;
TESTER m_tester;
};
main:
int main() {
tester_templatex<testerx, int> templatex1(p_type::p1);
tester_templatex<testerx, int, double> templatex2(p_type::p2);
tester_templatex<testerx, int, double, int> templatex3(p_type::p3);
templatex1.process(4);
templatex2.process(4, 5.123);
templatex3.process(4, 5.123, 6);
return 0;
}
Here I have test class with 3 different functions. I have a template class which picks the function to call based on the p_type (bad name - dont ask!).
This works for c++17 compiled code. But I only have c++11 where I need to run this code. c++11 does not support if constexpr:
case p_type::p3:
if constexpr (sizeof...(args) == 3)
m_tester.process3(args...);
break;
Without the if constexpr I get errors that the m_tester.process1/2/3 functions that don't match the parameter pack because they don't have the right number of parameters.
How can I fix this for c++11? - is it possible with a similar method?
Is there another way to extract N arguments from a parameter pack in c++11? - or some sort of type traits check?
For each of your functions have an overload that does nothing:
template<typename... ARGS>
void process3(ARGS&...) { }
and then just call the function without testing for the size of the pack:
case p_type::p3:
m_tester.process3(args...);
break;
This should pick the non-templated function when there are suitably many arguments, and the function template in other cases.
I put all codes in main.cpp, it run successfully. However, I separated them into different header file and cpp files, there was a error message:
2 duplicate symbols for architecture x86_64. I suppose I made mistakes in marcos.
There is the error message :
duplicate symbol __ZN2w13MAXE in:
/var/folders/f0/_q5s1yn17g55dkdhg7bd80xr0000gn/T/w1-7ce6b5.o
/var/folders/f0/_q5s1yn17g55dkdhg7bd80xr0000gn/T/CString-b6e225.o
ld: 1 duplicate symbol for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
//CString.h
#ifndef _CSTRING_H_
#define _CSTRING_H_
#include<iostream>
namespace w1{
extern const int MAX = 3;
class CString{
char* _s;
public:
CString(const char *);
void display(std::ostream&) const;
~CString(){if (_s != nullptr) delete [] _s;}
};
std::ostream& operator<<(std::ostream&, CString&);
}
#endif
//CString.cpp
#include"CString.h"
namespace w1{
CString::CString(const char* s){
if (s != nullptr){
_s = new char [MAX];
for(int i = 0; i < MAX; i++)
_s[i] = s[i];
}
else
_s = nullptr;
}
void CString::display(std::ostream& os) const{
if(_s != nullptr)
os << _s << std::endl;
else
os << "The string is empty." << std::endl;
}
std::ostream& operator<<(std::ostream& os, CString& target) {
target.display(os);
return os;
}
}
//main.cpp
#include"CString.h"
using namespace w1;
void process(const char* );
void process( const char* s){
w1::CString instance(s);
std::cout << instance << std::endl;
}
int main(int argc, char *argv[]){
if (argc == 1)
std::cout << "Insufficient number of arguments (min 1)" << std::endl;
else{
std::cout << "Maximum number of characters stored : " << w1::MAX <<std::endl;
for (int i = 1; i < argc; i++){
std::cout << i << ": ";
process(argv[i]);
}
}
return 0;
}
I have a struct that looks like this.
typedef struct superCellBoxStruct {
float_tt cmx,cmy,cmz; /* fractional center of mass coordinates */
float_tt ax,by,cz;
boost::shared_ptr<std::vector<atom>> atoms; /* contains all the atoms within the super cell */
} superCellBox;
now when I want to access atoms[i] I get
error: invalid use of ‘boost::detail::sp_array_access >::type {aka void}’
What is the proper way of passing around a shared vector in my application, or what is the correct way to access its operator[]?
Pick one:
(*atoms)[i]
atoms->operator[](i);
I usually go with the first, but they are all equivalent.
As a side note, in my experience a shared_ptr<vector> like that is usually a symptom of a bad design, maybe you want to put the entire superCellBox in a shared_ptr?
Also, this is not C, use struct name {}; instead typedef struct tagName {} name;
Prefer unique_ptr<T[]> if you can, because you get operator[] for free (§ 20.7.1.3.3):
Quick demo:
Live On Coliru
#include <memory>
#include <iostream>
int main() {
std::unique_ptr<int[]> p(new int[3] { 1,2,3 });
std::cout << "Before: " << p[0] << ", " << p[1] << ", " << p[2] << ";\n";
p[1] = 42;
std::cout << "After: " << p[0] << ", " << p[1] << ", " << p[2] << ";\n";
}
Prints:
Before: 1, 2, 3;
After: 1, 42, 3;
UPDATE
In response to the comment, just make a small wrapper:
Live On Coliru
#include <memory>
template <typename RAContainer> struct shared_randomaccess_container
{
template <typename... A> shared_randomaccess_container(A&&... args)
: _ptr(new RAContainer{ std::forward<A>(args)... })
{ }
template <typename T> shared_randomaccess_container(std::initializer_list<T> init)
: _ptr(std::make_shared<RAContainer>(init))
{ }
auto begin() const -> typename RAContainer::const_iterator { return _ptr->begin(); }
auto end () const -> typename RAContainer::const_iterator { return _ptr->end (); }
auto begin() -> typename RAContainer::iterator { return _ptr->begin(); }
auto end () -> typename RAContainer::iterator { return _ptr->end (); }
template <typename Idx>
typename RAContainer::value_type const& operator[](Idx i) const { return (*_ptr)[i]; }
template <typename Idx>
typename RAContainer::value_type& operator[](Idx i) { return (*_ptr)[i]; }
template <typename Idx>
typename RAContainer::value_type const& at(Idx i) const { return _ptr->at(i); }
template <typename Idx>
typename RAContainer::value_type& at(Idx i) { return _ptr->at(i); }
protected:
using Ptr = std::shared_ptr<RAContainer>;
Ptr _ptr;
};
////////////////////////////////////////////////////
// demo intances
#include <vector>
template <typename... Ts> using shared_vector = shared_randomaccess_container<std::vector<Ts...> >;
You can use it like:
shared_vector<int> sv {1,2,3};
std::cout << "Before: ";
for (auto i : sv) std::cout << i << " ";
sv[1] = 42;
std::cout << "\nAfter: ";
for (auto i : sv) std::cout << i << " ";
Prints:
Before: 1 2 3
After: 1 42 3
Bonus
Let's also support aggregate initializing containers with the same technique
Live On Coliru
Output:
void test() [with With = std::vector<int>]
Before: 1 2 3
After: 1 42 3
void test() [with With = std::array<int, 3ul>]
Before: 1 2 3
After: 1 42 3
void test() [with With = shared_randomaccess_container<std::vector<int>, false>]
Before: 1 2 3
After: 1 42 3
void test() [with With = shared_randomaccess_container<std::array<int, 3ul>, true>]
Before: 1 2 3
After: 1 42 3
How do I achieve the Qt::UniqueConnection mechanism in Boost?
Basically, I only want to connect the signal for only once.
As far as I know, there's no such thing, but you can easily mimic it using a custom combiner.
1. Using the custom Combiner
You can just ignore any excess slots. This combiner, for example, just ignores anything beyond the first slot (that is, the first added with at_front and no group, or the first in the group with the highest priority, see Ordering Slot Call Groups):
template<typename Result>
struct call_first {
typedef boost::optional<Result> result_type;
template<typename It>
result_type operator()(It first, It last) const {
if (first != last)
return *first;
return boost::none;
}
};
Now here's a test case: Live On Coliru
#include <iostream>
#include <boost/optional/optional_io.hpp>
int foo(int i) { std::cout << "(foo)"; return i*2; }
int bar(int i) { std::cout << "(bar)"; return i+2; }
int main()
{
using namespace boost::signals2;
signal<int(int), call_first<int> > sig;
std::cout << sig(42) << "\n"; // should be none ("--")
sig.connect(foo);
std::cout << sig(42) << "\n"; // should return 42*2
sig.connect(bar);
std::cout << sig(42) << "\n"; // should still return 42*2
}
Printing
--
(foo) 84
(foo) 84
2. Fix your connection management
You can make it easy to avoid double-connecting a signal, by using pretty simple helpers (assuming c++11 for this sample):
template <typename Sig, typename F> void try_connect(Sig& sig, F&& f) {
if (!sig.num_slots()) sig.connect(std::forward<F>(f));
}
template <typename Sig, typename F> void re_connect(Sig& sig, F&& f) {
sig.disconnect_all_slots();
sig.connect(std::forward<F>(f));
}
The corresponding test case Live On Coliru:
int main()
{
using namespace boost::signals2;
signal<int(int)> sig;
std::cout << sig(42) << "\n"; // should be none ("--")
try_connect(sig, foo);
std::cout << sig(42) << "\n"; // should return 42*2
try_connect(sig, bar);
std::cout << sig(42) << "\n"; // should still return 42*2
re_connect(sig, bar);
std::cout << sig(42) << "\n"; // should return 42+2
}
Output:
--
(foo) 84
(foo) 84
(bar) 44
I'm playing with the constexpr keyword and coded the following simple program:
#include <iostream>
using namespace std;
template<typename T>
constexpr bool is_equal(T const* array1, T const* array2, size_t len)
{
return array1 == array2 || (len ? array1[len - 1] == array2[len - 1] && is_equal<T>(array1, array2, len - 1) : true);
}
template<typename T, size_t N1, size_t N2>
constexpr bool is_equal(T const (&array1)[N1], T const (&array2)[N2])
{
return N1 == N2 && is_equal<T>(array1, array2, N1);
}
template<typename T, size_t N>
constexpr size_t arraylength(T const (&array)[N])
{
return N;
}
constexpr size_t stringlength(char const* str, size_t len=0)
{
return str ? (*str ? stringlength(str + 1, len + 1) : len) : 0;
}
constexpr size_t min(size_t one, size_t another)
{
return one < another ? one : another;
}
constexpr size_t min_length(char const* str1, char const* str2)
{
return min(stringlength(str1), stringlength(str2));
}
template<typename T, size_t N1, size_t N2>
constexpr size_t min_length(T const (&array1)[N1], T const (&array2)[N2])
{
return min(N1, N2);
}
template<bool cond=false>
struct to_num
{
enum {value=0};
};
template<>
struct to_num<true>
{
enum {value=42};
};
template<size_t init>
struct two_times
{
enum {value=init*2};
};
static constexpr char x[]{"One string"};
static constexpr char y[]{"One string"};
static constexpr int a[]{1,2,3,4};
static constexpr int b[]{1,2,3,4};
static constexpr int const* const c = &a[0];
static constexpr int const* const d = &b[0];
int main()
{
cout << "The two literals are equal: " << to_num< is_equal("One string", "One string") >::value << endl; // COMPILES AND WORKS IN GCC BUT NOT IN CLANG
cout << "The two variables x & y are equal: " << to_num< is_equal(x, y) >::value << endl;
cout << "Pointers a & c are equal: " << to_num< a == c >::value << endl;
cout << "Pointers b & c are equal: " << to_num< b == c >::value << endl;
cout << "Pointers c & d are equal: " << to_num< c == d >::value << endl;
cout << "The contents of c & d is the same: " << to_num< is_equal(c, d, arraylength(a)) >::value << endl;
cout << "Pointers a & b are equal: " << to_num< a == b >::value << endl;
cout << "The contents of a & b is the same: " << to_num< is_equal(a, b) >::value << endl;
cout << "String x contains " << two_times< stringlength(x) >::value / 2 << " characters" << endl; // COMPILES AND WORKS IN CLANG BUT NOT IN GCC
cout << "String literal contains " << two_times< stringlength("literal") >::value / 2 << " characters" << endl; // COMPILES AND WORKS IN CLANG BUT NOT IN GCC
cout << "Array literal contains " << two_times< arraylength("literal") >::value / 2 << " values" << endl;
return 0;
}
As the comments remark, some code compiles and works ok with g++ but not with clang++ and other compiles and work ok with clang++ but not with g++
The gcc error is:
comaprison.cpp: In function ‘int main()’:
comaprison.cpp:97:62: in constexpr expansion of ‘stringlength(((const char*)(& x)), 0ul)’
comaprison.cpp:29:55: in constexpr expansion of ‘stringlength((str + 1u), (len + 1ul))’
comaprison.cpp:97:64: error: ‘((((const char*)(& x)) + 1u) != 0u)’ is not a constant expression
cout << "String x contains " << two_times< stringlength(x) >::value / 2 << " characters" << endl;
^
comaprison.cpp:97:64: note: in template argument for type ‘long unsigned int’
comaprison.cpp:98:76: in constexpr expansion of ‘stringlength(((const char*)"literal"), 0ul)’
comaprison.cpp:29:55: in constexpr expansion of ‘stringlength((str + 1u), (len + 1ul))’
comaprison.cpp:98:78: error: ‘((((const char*)"literal") + 1u) != 0u)’ is not a constant expression
cout << "String literal contains " << two_times< stringlength("literal") >::value / 2 << " characters" << endl; // COMPILES AND WORKS IN CLANG BUT NOT IN GCC
^
comaprison.cpp:98:78: note: in template argument for type ‘long unsigned int’
and the clang++ one is:
comaprison.cpp:89:55: error: non-type template argument is not a constant expression
cout << "The two literals are equal: " << to_num< is_equal("One string", "One string") >::value << ...
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
comaprison.cpp:8:19: note: subexpression not valid in a constant expression
return array1 == array2 || (len ? array1[len - 1] == array2[len - 1] && is_equal<T>(array1, array2...
^
comaprison.cpp:14:24: note: in call to 'is_equal(&"One string"[0], &"One string"[0], 11)'
return N1 == N2 && is_equal<T>(array1, array2, N1);
^
comaprison.cpp:89:55: note: in call to 'is_equal("One string", "One string")'
cout << "The two literals are equal: " << to_num< is_equal("One string", "One string") >::value << ...
^
1 error generated.
g++ is "gcc version 4.8.1 (Ubuntu/Linaro 4.8.1-10ubuntu9)",
clang++ is "Ubuntu clang version 3.4-1ubuntu1 (trunk) (based on LLVM 3.4)"
Both in a x86_64 linux.
The command lines are:
clang++ -std=c++11 -o comaprison comaprison.cpp
g++ -std=c++11 -o comaprison comaprison.cpp
So, am I doing anything outside the c++11 standard with this code or there is something wrong in both compilers?.
Note that If I remove the g++ problematic lines but leave the clang++ problematic one, the code compiles and works with g++ and if I remove the clang++ problematic line and leave the g++ problematic ones, the code compiles and works ok with clang++
Note also that I'm using the two templated structs to force the compiler to resolve the functions at compile time.
Thank you for your time and experience.
Update:
GCC chokes on your function stringlength. Try this:
constexpr size_t stringlength(char const* str, size_t i=0)
{
return str ? (str[i] ? 1 + stringlength(str, i+1) : 0) : 0;
}
To GCC 4.6.3 this seems dubious:
static constexpr int const* c = &a[0];
static constexpr int const* d = &b[0];
Try this:
static constexpr int* c = &a[0];
static constexpr int* d = &b[0];
Old answer:
You code seems to be correct and with GCC 4.6.3 it also compiles.
int main()
{
const char* a = "hallo";
const char* b = "qallo";
std::cout << is_equal(a,b,5) << std::endl;
constexpr const char* c = "hallo";
std::cout << is_equal(a,c,5) << std::endl;
}
Be careful, that the strings you are giving to your functions are constants.
See here what is allowed with constexpr.
Your arraylength example that you say doesn't work with GCC, works just fine with GCC 4.7 and 4.8, and except for an unrelated error about constexpr const, also with GCC 4.6.
As for your stringlength example: this is a limitation of GCC. I know I've seen a bug report about it already. You can work around it by rewriting your stringlength function:
constexpr size_t stringlength(char const* str, size_t len=0)
{
return str ? (str[len] ? stringlength(str, len + 1) : len) : 0;
}
but as far as I can tell, what you had already was perfectly valid.