Rework std::initializer_list handling to warn about usage in any method, not just constructors. A typemap is used to issue the warning and can be overridden with user defined behaviour.
This commit is contained in:
parent
c8ff23de0c
commit
d613ef42f2
10 changed files with 259 additions and 134 deletions
|
|
@ -125,53 +125,133 @@ public:
|
|||
|
||||
<H3><a name="Cpp0x_Initializer_lists"></a>7.2.4 Initializer lists</H3>
|
||||
|
||||
|
||||
<p>
|
||||
Constructors using the std::initializer_list class are removed
|
||||
from the wrapped class because the only way to access such a
|
||||
constructor is at compile time using the initialization list syntax.
|
||||
Initializer lists are very much a C++ construct and not very accessible from wrappers.
|
||||
Initializer lists are very much a C++ compiler construct and are not very accessible from wrappers as
|
||||
they are intended for compile time initialization of classes using the special <tt>std::initializer_list</tt> type.
|
||||
SWIG detects usage of initializer lists and will emit a special informative warning each time one is used:
|
||||
</p>
|
||||
|
||||
<p>For now, if you want to fill the class components like this:</p>
|
||||
<div class="shell">
|
||||
<pre>
|
||||
example.i:33: Warning 476: Initialization using std::initializer_list.
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Initializer lists usually appear in constructors but can appear in any function or method.
|
||||
They often appear in constructors which are overloaded with alternative approaches to initializing a class,
|
||||
such as the std container's push_back method for adding elements to a container.
|
||||
The recommended approach then is to simply ignore the initializer-list constructor, for example:
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
class A {
|
||||
%ignore Container::Container(std::initializer_list<int>);
|
||||
class Container {
|
||||
public:
|
||||
A( std::initializer_list<int> );
|
||||
Container(std::initializer_list<int>); // initializer-list constructor
|
||||
Container();
|
||||
void push_back(const int &);
|
||||
...
|
||||
};
|
||||
A a1 = {1,2,3,4};
|
||||
</pre></div>
|
||||
|
||||
<p>you could add another constructor using <tt>std::vector</tt> for example:</p>
|
||||
<p>Alternatively you could modify the class and add another constructor for initialization by some other means,
|
||||
for example by a <tt>std::vector</tt>:</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
class A {
|
||||
%include <std_vector.i>
|
||||
class Container {
|
||||
public:
|
||||
A( std::initializer_list<int> );
|
||||
A( std::vector<int> );
|
||||
Container(const std::vector<int> &);
|
||||
Container(std::initializer_list<int>); // initializer-list constructor
|
||||
Container();
|
||||
void push_back(const int &);
|
||||
...
|
||||
};
|
||||
A a1 = {1,2,3,4};
|
||||
</pre></div>
|
||||
|
||||
<p>And then construct it from your target language, for example, in Python:</p>
|
||||
<p>And then call this constructor from your target language, for example, in Python, the following will call the constructor taking the <tt>std::vector</tt>:</p>
|
||||
|
||||
<div class="targetlang"><pre>
|
||||
>>> a2 = A( [1,2,3,4] )
|
||||
>>> c = Container( [1,2,3,4] )
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
<tt>std::initializer_list</tt> is simply a container that can only be initialised at compile time.
|
||||
As such it is possible to write typemaps for a target language container to map onto
|
||||
<tt>std::initializer_list</tt>. However, this can only be done for a fixed number of elements ...
|
||||
there is no way to construct an initializer list with a variable number of arguments at runtime.
|
||||
This is not particularly flexible though outside of C++ static initialization,
|
||||
hence the need to provide an alternative for use from a target language.
|
||||
If you are unable to modify the class being wrapped, consider ignoring the initializer-list constructor and using
|
||||
%extend to add in an alternative constructor:
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
%include <std_vector.i>
|
||||
%extend Container {
|
||||
Container(const std::vector<int> &elements) {
|
||||
Container *c = new Container();
|
||||
for (int element : elements)
|
||||
c->push_back(element);
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
%ignore Container::Container(std::initializer_list<int>);
|
||||
|
||||
class Container {
|
||||
public:
|
||||
Container(std::initializer_list<int>); // initializer-list constructor
|
||||
Container();
|
||||
void push_back(const int &);
|
||||
...
|
||||
};
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
The above makes the wrappers look is as if the class had been declared as follows:
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
%include <std_vector.i>
|
||||
class Container {
|
||||
public:
|
||||
Container(const std::vector<int> &);
|
||||
// Container(std::initializer_list<int>); // initializer-list constructor (ignored)
|
||||
Container();
|
||||
void push_back(const int &);
|
||||
...
|
||||
};
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
<tt>std::initializer_list</tt> is simply a container that can only be initialized at compile time.
|
||||
As it is just a C++ type, it is possible to write typemaps for a target language container to map onto
|
||||
<tt>std::initializer_list</tt>. However, this can only be done for a fixed number of elements as
|
||||
initializer lists are not designed to be constructed with a variable number of arguments at runtime.
|
||||
The example below is a very simple approach which ignores any parameters passed in and merely initializes
|
||||
with a fixed list of fixed integer values chosen at compile time:
|
||||
</p>
|
||||
|
||||
<div class="code"><pre>
|
||||
%typemap(in) std::initializer_list<int> {
|
||||
$1 = {10, 20, 30, 40, 50};
|
||||
}
|
||||
class Container {
|
||||
public:
|
||||
Container(std::initializer_list<int>); // initializer-list constructor
|
||||
Container();
|
||||
void push_back(const int &);
|
||||
...
|
||||
};
|
||||
</pre></div>
|
||||
|
||||
<p>
|
||||
Any attempt at passing in values from the target language will be ignored and replaced by <tt>{10, 20, 30, 40, 50}</tt>.
|
||||
Needless to say, this approach is very limited, but could be improved upon, but only slightly.
|
||||
A typemap could be written to map a fixed number of elements on to the <tt>std::initializer_list</tt>,
|
||||
but with values decided at runtime.
|
||||
The typemaps would be target language specific.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Initializer lists can appear in any function or method, not just constructors.
|
||||
SWIG only ignores the constructors as this is where they commonly occur.
|
||||
Users are recommended to manually ignore any other methods using an initialization list with <tt>%ignore</tt>.
|
||||
Note that the default typemap for <tt>std::initializer_list</tt> does nothing but issue the warning
|
||||
and hence any user supplied typemaps will override it and suppress the warning.
|
||||
</p>
|
||||
|
||||
<H3><a name="Cpp0x_Uniform_initialization"></a>7.2.5 Uniform initialization</H3>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue