Building on top of this example:
https://www.boost.org/doc/libs/1_75_0/libs/geometry/doc/html/geometry/spatial_indexes/rtree_examples/using_indexablegetter_function_object___storing_indexes_of_external_container_s_elements.html
I have constructed the following MWE to build and query spatial trees based on indices onto non-trivial containers. The example this was based upon assumes that Container::value_type is already a leaf of the tree. I simply adapted the example to work with any indexable type, i.e., any type understood by bgi::indexable<typename Container::value_type>.
The included MWE works just fine on Linux and Mac, but fails to compile on Windows, and I'm struggling in understanding what the problem may be. A working example is here https://godbolt.org/z/vTT5r5MWc, where you can see that if you switch to gcc or clang, everything works, but with MSVC19 we get the errors reported below.
Any idea on how to modify the IndexableGetter/anything else to make this work under MSVC?
#include <boost/geometry/index/rtree.hpp>
#include <boost/geometry/strategies/strategies.hpp>
#include <boost/range/irange.hpp>
#include <iostream>
namespace bg = boost::geometry;
namespace bgi = boost::geometry::index;
template <typename LeafType,
typename IndexType = bgi::linear<16>,
typename IndexableGetter = bgi::indexable<LeafType>>
using RTree = bgi::rtree<LeafType, IndexType, IndexableGetter>;
using Point = bg::model::point<double, 2, bg::cs::cartesian>;
template <typename Container>
class IndexableGetterFromIndices
{
public:
using IndexableGetter =
typename bgi::indexable<typename Container::value_type>;
using result_type = typename IndexableGetter::result_type;
using size_t = typename Container::size_type;
explicit IndexableGetterFromIndices(Container const &c)
: container(c)
{}
result_type
operator()(size_t i) const
{
return getter(container[i]);
}
private:
const Container &container;
IndexableGetter getter;
};
template <typename IndexType = boost::geometry::index::linear<16>,
typename ContainerType>
RTree<typename ContainerType::size_type,
IndexType,
IndexableGetterFromIndices<ContainerType>>
pack_rtree_of_indices(const ContainerType &container)
{
boost::integer_range<typename ContainerType::size_type> indices(
0, container.size());
return RTree<typename ContainerType::size_type,
IndexType,
IndexableGetterFromIndices<ContainerType>>(
indices.begin(),
indices.end(),
IndexType(),
IndexableGetterFromIndices<ContainerType>(container));
}
int
main()
{
std::vector<std::pair<Point, int>> points;
// create some points
for (unsigned i = 0; i < 10; ++i)
points.push_back(std::make_pair(Point(i + 0.0, i + 0.0), i * 10));
const auto tree = pack_rtree_of_indices(points);
for (const auto result :
tree | bgi::adaptors::queried(bgi::nearest(Point(3.0, 4.0), 1)))
{
std::cout << "Nearest point: " << bg::wkt<Point>(points[result].first)
<< ", index = " << points[result].second << std::endl;
}
}
The error I get on Windows is
example.cpp
C:/data/libraries/installed/x64-windows/include\boost/geometry/index/rtree.hpp(1762): error C2664: 'boost::geometry::index::detail::translator<IndexableGetter,EqualTo>::translator(const boost::geometry::index::indexable<std::pair<Point,int>> &,const EqualTo &)': cannot convert argument 1 from 'const IndGet' to 'const boost::geometry::index::indexable<std::pair<Point,int>> &'
with
[
IndexableGetter=IndexableGetterFromIndices<std::vector<std::pair<Point,int>,std::allocator<std::pair<Point,int>>>>,
EqualTo=boost::geometry::index::equal_to<std::_Default_allocator_traits<std::allocator<std::pair<Point,int>>>::size_type>
]
and
[
IndGet=IndexableGetterFromIndices<std::vector<std::pair<Point,int>,std::allocator<std::pair<Point,int>>>>
]
C:/data/libraries/installed/x64-windows/include\boost/geometry/index/rtree.hpp(1768): note: Reason: cannot convert from 'const IndGet' to 'const boost::geometry::index::indexable<std::pair<Point,int>>'
with
[
IndGet=IndexableGetterFromIndices<std::vector<std::pair<Point,int>,std::allocator<std::pair<Point,int>>>>
]
C:/data/libraries/installed/x64-windows/include\boost/geometry/index/rtree.hpp(1762): note: No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
C:/data/libraries/installed/x64-windows/include\boost/geometry/index/detail/translator.hpp(51): note: see declaration of 'boost::geometry::index::detail::translator<IndexableGetter,EqualTo>::translator'
with
[
IndexableGetter=IndexableGetterFromIndices<std::vector<std::pair<Point,int>,std::allocator<std::pair<Point,int>>>>,
EqualTo=boost::geometry::index::equal_to<std::_Default_allocator_traits<std::allocator<std::pair<Point,int>>>::size_type>
]
....
Thanks for a very neat self-contained example.
It does compile with /std::latest:
x86 msvc v19.latest, Live On Compiler Explorer).
x64 msvc v19.latest, Live On Compiler Explorer).
In retrospect there was the clue:
cl : Command line warning D9002 : ignoring unknown option '-std=c++2a'
Related
when reading the document of std::span, I see there is no method to remove the first element from the std::span<T>.
Can you suggest a way to solve my issue?
The large picture of my problem(I asked in another question: How to instantiatiate a std::basic_string_view with custom class T, I got is_trivial_v<_CharT> assert error) is that I would like to have a std::basic_string_view<Token>, while the Token is not a trivial class, so I can't use std::basic_string_view, and someone suggested me to use std::span<Token> instead.
Since the basic_string_view has a method named remove_prefix which remove the first element, while I also need such kinds of function because I would like to use std::span<Token> as a parser input, so the Tokens will be matched, and consumed one by one.
Thanks.
EDIT 2023-02-04
I try to derive a class named Span from std::span, and add the remove_prefix member function, but it looks like I still have build issues:
#include <string_view>
#include <vector>
#include <span>
// derived class, add remove_prefix function to std::span
template<typename T>
class Span : public std::span<T>
{
public:
// Inheriting constructors
using std::span<T>::span;
// add a public function which is similar to std::string_view::remove_prefix
constexpr void remove_prefix(std::size_t n) {
*this = subspan(n);
}
};
struct Token
{
Token(){};
Token(const Token& other)
{
lexeme = other.lexeme;
type = other.type;
}
std::string_view lexeme;
int type;
// equal operator
bool operator==(const Token& other)const {
return (this->lexeme == other.lexeme) ;
}
};
template <typename T>
struct Viewer;
template <>
struct Viewer<Token>
{
using type = Span<Token>; // std::span or derived class
};
template <>
struct Viewer<char>
{
using type = std::string_view;
};
template <typename T> using ViewerT = typename Viewer<T>::type;
template <typename T>
class Parser
{
using v = ViewerT<T>;
};
// a simple parser demo
template <typename Base, typename T>
struct parser_base {
using v = ViewerT<T>;
constexpr auto operator[](v& output) const noexcept;
};
template<typename T>
struct char_ final : public parser_base<char_<T>, T> {
using v = ViewerT<T>;
constexpr explicit char_(const T ch) noexcept
: ch(ch)
{}
constexpr inline bool visit(v& sv) const& noexcept {
if (!sv.empty() && sv.front() == ch) {
sv.remove_prefix(1);
return true;
}
return false;
}
private:
T ch;
};
template <typename Parser, typename T>
constexpr bool parse(Span<T> &input, Parser const& parser) noexcept {
return parser.visit(input);
}
int main()
{
Token kw_class;
kw_class.lexeme = "a";
std::vector<Token> token_stream;
token_stream.push_back(kw_class);
token_stream.push_back(kw_class);
token_stream.push_back(kw_class);
Span<Token> token_stream_view{&token_stream[0], 3};
auto p = char_(kw_class);
parse(token_stream_view, p);
return 0;
}
The build error looks like below:
[ 50.0%] g++.exe -Wall -std=c++20 -fexceptions -g -c F:\code\test_crtp_twoargs\main.cpp -o obj\Debug\main.o
F:\code\test_crtp_twoargs\main.cpp: In member function 'constexpr void Span<T>::remove_prefix(std::size_t)':
F:\code\test_crtp_twoargs\main.cpp:52:17: error: there are no arguments to 'subspan' that depend on a template parameter, so a declaration of 'subspan' must be available [-fpermissive]
52 | *this = subspan(n);
| ^~~~~~~
F:\code\test_crtp_twoargs\main.cpp:52:17: note: (if you use '-fpermissive', G++ will accept your code, but allowing the use of an undeclared name is deprecated)
F:\code\test_crtp_twoargs\main.cpp: In instantiation of 'constexpr void Span<T>::remove_prefix(std::size_t) [with T = Token; std::size_t = long long unsigned int]':
F:\code\test_crtp_twoargs\main.cpp:113:29: required from 'constexpr bool char_<T>::visit(v&) const & [with T = Token; v = Span<Token>]'
F:\code\test_crtp_twoargs\main.cpp:125:24: required from 'constexpr bool parse(Span<T>&, const Parser&) [with Parser = char_<Token>; T = Token]'
F:\code\test_crtp_twoargs\main.cpp:141:10: required from here
F:\code\test_crtp_twoargs\main.cpp:52:24: error: 'subspan' was not declared in this scope, and no declarations were found by argument-dependent lookup at the point of instantiation [-fpermissive]
52 | *this = subspan(n);
| ~~~~~~~^~~
F:\code\test_crtp_twoargs\main.cpp:52:24: note: declarations in dependent base 'std::span<Token, 18446744073709551615>' are not found by unqualified lookup
F:\code\test_crtp_twoargs\main.cpp:52:24: note: use 'this->subspan' instead
F:\code\test_crtp_twoargs\main.cpp:52:15: error: no match for 'operator=' (operand types are 'Span<Token>' and 'std::span<Token, 18446744073709551615>')
52 | *this = subspan(n);
| ~~~~~~^~~~~~~~~~~~
F:\code\test_crtp_twoargs\main.cpp:44:7: note: candidate: 'constexpr Span<Token>& Span<Token>::operator=(const Span<Token>&)'
44 | class Span : public std::span<T>
| ^~~~
F:\code\test_crtp_twoargs\main.cpp:44:7: note: no known conversion for argument 1 from 'std::span<Token, 18446744073709551615>' to 'const Span<Token>&'
F:\code\test_crtp_twoargs\main.cpp:44:7: note: candidate: 'constexpr Span<Token>& Span<Token>::operator=(Span<Token>&&)'
F:\code\test_crtp_twoargs\main.cpp:44:7: note: no known conversion for argument 1 from 'std::span<Token, 18446744073709551615>' to 'Span<Token>&&'
Any idea on how to fix this issue?
Also, I don't know how to make a general parse function:
template <typename Parser, typename T>
constexpr bool parse(Span<T> &input, Parser const& parser) noexcept {
return parser.visit(input);
}
Currently, the first argument of the parse should be a Viewer like type?
EDIT2023-02-05
Change the function as below, the above code can build correctly. This is from Benjamin Buch's answer.
constexpr void remove_prefix(std::size_t n) {
auto& self = static_cast<std::span<T>&>(*this);
self = self.subspan(n);
}
There is still one thing remains: How to generalize the parse function to accept both input types of std::string_view and Span<Token>?
If I change the parse function to this:
template <typename Parser, typename T>
constexpr bool parse(ViewerT<T> &input, Parser const& parser) noexcept {
return parser.visit(input);
}
I got such compile error:
[ 50.0%] g++.exe -Wall -std=c++20 -fexceptions -g -c F:\code\test_crtp_twoargs\main.cpp -o obj\Debug\main.o
F:\code\test_crtp_twoargs\main.cpp: In function 'int main()':
F:\code\test_crtp_twoargs\main.cpp:143:24: error: no matching function for call to 'parse(Span<Token>&, char_<Token>&)'
143 | bool result = parse(token_stream_view, p);
| ~~~~~^~~~~~~~~~~~~~~~~~~~~~
F:\code\test_crtp_twoargs\main.cpp:125:16: note: candidate: 'template<class Parser, class T> constexpr bool parse(ViewerT<T>&, const Parser&)'
125 | constexpr bool parse(ViewerT<T> &input, Parser const& parser) noexcept {
| ^~~~~
F:\code\test_crtp_twoargs\main.cpp:125:16: note: template argument deduction/substitution failed:
F:\code\test_crtp_twoargs\main.cpp:143:24: note: couldn't deduce template parameter 'T'
143 | bool result = parse(token_stream_view, p);
| ~~~~~^~~~~~~~~~~~~~~~~~~~~~
Any ideas?
Thanks.
BTW: I have to explicitly instantiation of the parse function call like:
bool result = parse<decltype(p), Token>(token_stream_view, p);
to workaround this issue.
Call subspan with 1 as only (template) argument to get a new span, which doesn't contain the first element.
If you use a span with a static extend, you need a new variable because the data type changes by subspan.
#include <string_view>
#include <iostream>
#include <span>
int main() {
std::span<char const, 12> text_a("a test-span");
std::cout << std::string_view(text_a) << '\n';
std::span<char const, 10> text_b = text_a.subspan<2>();
std::cout << std::string_view(text_b) << '\n';
}
If you have a dynamic extend, you can assign the result to the original variable.
#include <string_view>
#include <iostream>
#include <span>
int main() {
std::span<char const> text("a test-span");
std::cout << std::string_view(text) << '\n';
text = text.subspan(2);
std::cout << std::string_view(text) << '\n';
}
The implementation of a modifying inplace subspan version is only possible for spans with a dynamic extend. It can be implemented as a free function.
#include <string_view>
#include <iostream>
#include <span>
template <typename T>
constexpr void remove_front(std::span<T>& self, std::size_t const n) noexcept {
self = self.subspan(n);
}
int main() {
std::span<char const> text("a test-span");
std::cout << std::string_view(text) << '\n';
remove_front(text, 2);
std::cout << std::string_view(text) << '\n';
}
You can use your own spans derived from std::span if you prefer the dot-call.
#include <string_view>
#include <iostream>
#include <span>
template <typename T>
struct my_span: std::span<T> {
using std::span<T>::span;
constexpr void remove_front(std::size_t const n) noexcept {
auto& self = static_cast<std::span<T>&>(*this);
self = self.subspan(n);
}
};
int main() {
my_span<char const> my_text("a test-span");
std::cout << std::string_view(my_text) << '\n';
my_text.remove_front(2);
std::cout << std::string_view(my_text) << '\n';
}
You can also write a wrapper class to call via dot syntax. This way you can additionally implement cascadable modification calls by always returning the a reference modifier class.
#include <string_view>
#include <iostream>
#include <span>
template <typename T>
class span_modifier {
public:
constexpr span_modifier(std::span<T>& span) noexcept: span_(span) {}
constexpr span_modifier& remove_front(std::size_t const n) noexcept {
span_ = span_.subspan(n);
return *this;
}
private:
std::span<T>& span_;
};
template <typename T>
constexpr span_modifier<T> modify(std::span<T>& span) noexcept {
return span;
}
int main() {
std::span<char const> text("a test-span");
std::cout << std::string_view(text) << '\n';
modify(text).remove_front(2).remove_front(5);
std::cout << std::string_view(text) << '\n';
}
Note I use the template function modify to create an object of the wrapper class, because the names of classes cannot be overloaded. Therefore class names should always be a bit more specific. The function modify can also be overloaded for other data types, which then return a different wrapper class. This results in a simple intuitive and consistent interface for modification wrappers.
You can write remove_prefix of your version,
template <typename T>
constexpr void remove_prefix(std::span<T>& sp, std::size_t n) {
sp = sp.subspan(n);
}
Demo
Consider the following example
#include <iostream>
#include <any>
#include <vector>
#include <map>
#include <typeinfo>
typedef enum TYPE{
INT8=0,
INT16=1,
INT32=2
} TYPE;
int main()
{
std::map<TYPE, std::any> myMap;
myMap[TYPE::INT8] = (int8_t)0;
myMap[TYPE::INT16] = (int16_t)0;
myMap[TYPE::INT32] = (int32_t)0;
std::vector<decltype(myMap[TYPE::INT8])> vec;
}
I have a map in this example, going from some enum to std::any. I actually need a flexible data structure that can map from a specific type (enum TYPE in this case), to multiple data types (different types of int), hence the use of std::any.
Going ahead, I would like to ascertain the type of value given for the key and construct a vector with it. I tried the above code, and it runs into a compilation error because decltype will return std::any(correctly so).
I would want to extract the "true type" from the std::any and create that type of vector. How would I achieve that.
A small snippet of the compilation error is as follows -
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/new_allocator.h:63:26: error: forming pointer to reference type 'std::any&'
63 | typedef _Tp* pointer;
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/new_allocator.h:112:7: error: forming pointer to reference type 'std::any&'
112 | allocate(size_type __n, const void* = static_cast<const void*>(0))
/opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/stl_vector.h:1293:7: error: 'void std::vector<_Tp, _Alloc>::push_back(value_type&&) [with _Tp = std::any&; _Alloc = std::allocator<std::any&>; value_type = std::any&]' cannot be overloaded with 'void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = std::any&; _Alloc = std::allocator<std::any&>; value_type = std::any&]'
1293 | push_back(value_type&& __x)
TIA
As suggested in the comments by #Ted Lyngmo, I think std::variant serves you better. Especially with C++-20's templated lambdas, the std::visit function can work wonders with these to get around the awkwardness of dealing with type enums and the like.
Note that you can not get around the runtime type detection. In any case, here is an example of how it can work.
#include <cstdint>
#include <iostream>
#include <variant>
#include <vector>
using VariantScalar = std::variant<
std::int8_t, std::int16_t, std::int32_t>;
using VariantVector = std::variant<
std::vector<std::int8_t>,
std::vector<std::int16_t>,
std::vector<std::int32_t>>;
VariantVector fill_vector(VariantScalar scalar, std::size_t n)
{
auto make_vector = [n]<class IntType>(IntType v) -> VariantVector {
return std::vector<IntType>(n, v);
};
return std::visit(make_vector, scalar);
}
void print_vector(const VariantVector& vec)
{
std::visit([]<class T>(const std::vector<T>& vec) {
for(const T& s: vec)
std::cout << s << ' ';
std::cout << '\n';
}, vec);
}
int main()
{
VariantScalar s(std::int8_t(1));
VariantVector vec = fill_vector(s, 5);
print_vector(vec);
}
Assuming you have the following enum definition:
enum class TYPE{
INT8=0,
INT16=1,
INT32=2
};
Then you can define a helper:
template <TYPE>
struct my_type {}; // Base case
template <>
struct my_type<TYPE::INT8> {
using type = int8_t;
};
template <>
struct my_type<TYPE::INT16> {
using type = int16_t;
};
template <>
struct my_type<TYPE::INT32> {
using type = int32_t;
};
template <TYPE t>
using my_type = typename my_type<t>::type;
That you can use for your vector
std::vector<my_type<TYPE::INT8>> vec;
The following code is a minimum working (or perhaps non-working) example.
What it does is basically encapsulates a bunch of std::map structures as private members in a base class. To avoid writing a lot of setters and getters, they are implemented as template functions.
// test.cpp
#include <map>
#include <iostream>
enum class E0
{
F0, F1, F2,
};
The declaration of the base class.
using std::map;
class P_base
{
private:
map<E0, int> m_imap;
// ...
// ... Other std::map members with different key types and value types.
public:
map<E0, int> & imap;
// ...
// ... Other std::map references.
P_base() : imap(m_imap) {}
template<typename map_type, typename key_type, typename val_type>
void set(map_type & m, const key_type & k, const val_type & v)
{
m[k] = v;
}
template<typename map_type, typename key_type>
auto access_to_map(const map_type & m, const key_type & k) -> decltype(m.at(k))
{
return m.at(k);
}
};
class P : private P_base
{
public:
decltype(P_base::imap) & imap;
P() : P_base(), imap(P_base::imap) {}
template<typename map_type, typename key_type, typename val_type>
void set(map_type & m, const key_type & k, const val_type & v)
{
P_base::set(m, k, v);
}
template<typename map_type, typename key_type>
auto access_to_map(const map_type & m, const key_type & k) -> decltype(P_base::access_to_map(m, k))
{
return P_base::access_to_map(m, k);
}
};
main
int main(int argc, const char * argv[])
{
using std::cout;
using std::endl;
P op;
op.set(op.imap, E0::F0, 100);
op.set(op.imap, E0::F1, 101);
op.set(op.imap, E0::F2, 102);
cout << op.access_to_map(op.imap, E0::F1) << endl;
}
$ clang++ -std=c++11 test.cpp && ./a.out
101
But if I compile it with intel compiler (icpc version 15.0.3 (gcc version 5.1.0 compatibility)), the compiler gives me this error message (which I don't undertand at all, especially when clang will compile the code):
$ icpc -std=c++ test.cpp && ./a.out
test.cpp(67): error: no instance of function template "P::access_to_map" matches the argument list
argument types are: (std::__1::map<E0, int, std::__1::less<E0>, std::__1::allocator<std::__1::pair<const E0, int>>>, E0)
object type is: P
cout << op.access_to_map(op.imap, E0::F1) << endl;
And it also confuses me by not complaining about the set function.
Does anyone have any idea what is going on here?
Note: My answer applies to g++ - hopefully it's the same as icc.
Here is a smaller test case:
struct Base
{
int func(int t) { return t; }
};
struct Der : Base
{
template<typename T>
auto f(T t) -> decltype(Base::func(t))
{
return t;
}
};
int main(){ Der d; d.f(5); }
The error is:
mcv.cc: In function 'int main()':
mcv.cc:16:25: error: no matching function for call to 'Der::f(int)'
int main(){ Der d; d.f(5); }
^
mcv.cc:16:25: note: candidate is:
mcv.cc:9:7: note: template<class T> decltype (t->Base::func()) Der::f(T)
auto f(T t) -> decltype(Base::func(t))
^
mcv.cc:9:7: note: template argument deduction/substitution failed:
mcv.cc: In substitution of 'template<class T> decltype (t->Base::func()) Der::f(T) [with T = int]':
mcv.cc:16:25: required from here
mcv.cc:9:38: error: cannot call member function 'int Base::func(int)' without object
auto f(T t) -> decltype(Base::func(t))
This can be fixed by changing decltype(Base::func(t)) to decltype(this->Base::func(t)). A corresponding fix fixes your code sample, for me.
Apparently, the compiler doesn't consider that Base::func(t) should be called with *this as hidden argument. I don't know if this is a g++ bug, or if clang is going beyond the call of duty.
Note that in C++14, since the function has a single return statement, the trailing return type can be omitted entirely:
template<typename T>
auto f(T t)
{
return t;
}
I'm trying to implement a simple N-dimensional array. This seems to be working more or less properly but I just can't get its overloaded ostream operator work. Here's my current implementation:
#include <iostream>
#include <memory>
#include <vector>
template <typename Type, int Dimension>
struct Array {
typedef std::vector<typename Array<Type, Dimension - 1>::type> type;
template <typename cType, int cDimension>
friend std::ostream &operator<<(std::ostream &stream, const Array<cType, cDimension>::type &object) {
if (cDimension == 0) {
stream << object << ' ';
} else {
typedef typename Array<cType, cDimension>::type::iterator ArrayIterator;
for (ArrayIterator it = object.begin(); it != object.end(); ++it) {
typedef typename Array<cType, cDimension - 1>::type NestedArray;
NestedArray nArray = (NestedArray)(*it);
stream << nArray << std::endl;
}
}
return stream;
}
};
template <typename Type>
struct Array < Type, 0 > {
typedef Type type;
};
int main() {
Array<int, 1>::type c00 = { 1, 2, 3 };
Array<int, 1>::type c01 = { 2, 3, 4 };
Array<int, 1>::type c02 = { 3, 4, 5 };
Array<int, 2>::type c10 = { c00, c01 };
Array<int, 2>::type c11 = { c01, c02 };
Array<int, 3>::type c20 = { c10, c11 };
std::cout << c20 << std::endl;
return 0;
}
I'm getting the following compilation errors:
1>------ Build started: Project: NDepthArray, Configuration: Debug Win32 ------
1> Source.cpp
1>c:\users\Administrator\documents\visual studio 2013\projects\cppmaterials\ndeptharray\source.cpp(10): warning C4346: 'Array<Type,Dimension>::type' : dependent name is not a type
1> prefix with 'typename' to indicate a type
1> c:\users\Administrator\documents\visual studio 2013\projects\cppmaterials\ndeptharray\source.cpp(25) : see reference to class template instantiation 'Array<Type,Dimension>' being compiled
1>c:\users\Administrator\documents\visual studio 2013\projects\cppmaterials\ndeptharray\source.cpp(10): error C2061: syntax error : identifier 'type'
1>c:\users\Administrator\documents\visual studio 2013\projects\cppmaterials\ndeptharray\source.cpp(10): error C2805: binary 'operator <<' has too few parameters
1>c:\users\Administrator\documents\visual studio 2013\projects\cppmaterials\ndeptharray\source.cpp(10): fatal error C1903: unable to recover from previous error(s); stopping compilation
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
I literally tried all my ideas already, which includes removing friend keyword and the actual class parameter but nothing changes. How can we overload operators for such class templates?
Cheers,
Joey
The problem with your approach is that the cType cannot be inferred:
template <typename Type, int Dimension> // Asking for Type as cType
struct Array {
typedef std::vector<typename Array<Type, Dimension - 1>::type> type;
}
template <typename cType, int cDimension> ↓↓↓↓↓
std::ostream &operator<<(std::ostream &stream, typename Array<cType, cDimension>::type &object)
Array<int, 3>::type c20 = { c10, c11 };
std::cout << c20 // Deduction failure
You can find more info here: https://stackoverflow.com/a/12566268/1938163
14.8.2.5/4
In certain contexts, however, the value does not participate in type
deduction, but instead uses the values of template arguments that were
either deduced elsewhere or explicitly specified. If a template
parameter is used only in non-deduced contexts and is not explicitly
specified, template argument deduction fails.
As a sidenote: implementing complex structures for multidimensional arrays or vectors with templated recursive code is a not-very-maintainable and surely hard-to-read path to achieve something that could have been done faster, more efficient (less allocations) and clearer with only a contiguous block of memory indexed in different strides.
I have a list of boost::tuple. I want to expose this tuple list to Java bindings through SWIG. But when I try to compile mt wrap.cxx, generated by SWIG, I get following errors:
d:\xyz\...\vector.h(115) : error C2678: binary '==' : no operator found which takes a left-hand operand of type 'const boost::tuples::tuple<T0,T1>' (or there is no acceptable conversion)
with
[
T0=std::string,
T1=std::string
]
c:\program files\microsoft visual studio 8\vc\platformsdk\include\guiddef.h(192): or 'int operator ==(const GUID &,const GUID &)'
while trying to match the argument list '(const boost::tuples::tuple<T0,T1>, const MyTuple)'
with
[
T0=std::string,
T1=std::string
]
d:\xyz\...\vector.h(111) : while compiling class template member function 'int Vector<T>::index(const T &) const'
with
[
T=MyTuple
]
d:\xyz\...\MyTuple_wrap.cxx(17731) : see reference to class template instantiation 'Vector<T>' being compiled
with
[
T=MyTuple
]
Can anyone tell me what I should do to resolve this issue?
It is unclear how you arrived at the error you've shown. boost::tuple is tricky to wrap by default and there doesn't seem to be any standard interface to it included with SWIG. In my tests I couldn't get close to the error you were seeing without manually writing an interface file.
I did however succeeded in wrapping boost's tuples using the following interface file:
%{
#include <boost/tuple/tuple.hpp>
%}
namespace boost {
template <typename T1=void, typename T2=void, typename T3=void>
struct tuple;
template <>
struct tuple<void,void,void> {
};
template <typename T1>
struct tuple<T1, void, void> {
tuple(T1);
%extend {
T1 first() const {
return boost::get<0>(*$self);
}
}
};
template <typename T1, typename T2>
struct tuple <T1, T2, void> {
tuple(T1,T2);
%extend {
T1 first() const {
return boost::get<0>(*$self);
}
T2 second() const {
return boost::get<1>(*$self);
}
}
};
template <typename T1, typename T2, typename T3>
struct tuple <T1,T2,T3> {
tuple(T1,T2,T3);
%extend {
T1 first() const {
return boost::get<0>(*$self);
}
T2 second() const {
return boost::get<1>(*$self);
}
T3 third() const {
return boost::get<2>(*$self);
}
}
};
}
Basically all it does is add accessor functions to each of the specialisations of tuple you might care about. It's sufficient to make it minimally useful in Java or some other language. You would want to expand on this to cover larger tuples. You probably want to make the member functions get/set if your tuples aren't intended to be immutable.
I was able to test this with a SWIG module:
%module test
%include "boost_tuple.i"
%template(TestTuple) boost::tuple<int, double, char>;
%template(SingleTuple) boost::tuple<char>;
%inline %{
boost::tuple<int, double, char> func1() {
return boost::make_tuple(3, 2.0, '1');
}
void test1(boost::tuple<int, double, char>) {
}
%}
Which worked as expected with the following Java:
public class run {
public static void main(String[] argv) {
System.loadLibrary("test");
TestTuple t = test.func1();
System.out.println("1: " + t.first() + " 2: " + t.second() + " 3: " + t.third());
test.test1(test.func1());
test.test1(new TestTuple(0, 0.0, '0'));
}
}