Default value for template function argument - c++

Caution: I don't have C++11
I need a default value for a template function parameter, but it seems c++
will skip deduction for default parameters...
struct mode1 {};
struct mode2 {};
template <typename T>
void myFunc(int value, T mode = mode1())
{
if(std::is_same<T, mode1>::value)
{
std::cout << "foo";
}
else if(std::is_same<T, mode2>::value)
{
std::cout << "bar";
}
}
But how can i achieve, that this call will work:
myFunc(20); /* Defaults to mode1 */
Why i will use this? Because of optimization...
In my real life scenario, i would use this for this piece of code:
template <typename TokenType>
HGStringBasic Tokenize(const _ElemT* tokens, size_type uTokenIndex, size_type uIndex = 0, size_type uEndIndex = npos, TokenType tokenType = tokenTypeChar()) const
{
size_type uPosInStr;
size_type uCurrToken;
if(uEndIndex == npos)
{
uEndIndex = this->Length();
}
for( uCurrToken = 0 ; uIndex < uEndIndex ; (uIndex = uPosInStr+1), (++uCurrToken) )
{
if(std::is_same<TokenType, tokenTypeChar>::value)
uPosInStr = this->PosBrk(tokens, uIndex);
else if(std::is_same<TokenType, tokenTypeString>::value)
uPosInStr = this->Pos(tokens, uIndex);
if(uCurrToken == uTokenIndex)
{
if(uPosInStr == npos)
return this_type(&m_data[uIndex], uEndIndex - uIndex);
return this_type(&m_data[uIndex], (uPosInStr < uEndIndex ? uPosInStr : uEndIndex) - uIndex);
}
if(uPosInStr == npos)
break;
}
return this_type();
}

Yes, default value is not considered in template arugment deduction.
Type template parameter cannot be deduced from the type of a function default argument
You can add an overload, e.g.
template <typename T>
void myFunc(int value, T mode)
{
...
}
void myFunc(int value) {
myFunc(value, mode1());
}

Related

How to enable template parameter if optional function parameter is set?

I have a parsing function that I want to branch based on whether a length option is set or not. If the length option is set, the function should always check if the decreased length equals to 0. If not, it only checks for null termination. Based on this little detail I don't want to rewrite my whole function, so here's what I came up with:
#include <iostream>
const char* str = "some random string";
template <bool LengthOpt = false>
void parse(const char* ch, size_t len = 0)
{
while ( 1 ) {
if constexpr(LengthOpt) {
if ( len == 0 ) {
std::cout << std::endl;
return ;
} else {
len--;
}
} else {
if ( !(*ch) ) {
std::cout << std::endl;
return ;
}
}
std::cout << *ch;
++ch;
/* big part starts here */
}
}
int main()
{
parse<true>(str, 5);
parse(str);
}
godbolt
What bugs me is that I always have to specify both, length AND template parameter to go with the length option. So I'm wondering:
Is there a way to constexpr branch based on whether an optional parameter is set or not?
Could I infer template parameters from whether the optional parameter is set?
Note: This is a contrived example showing just the detail. I've added comments in the code where the actual parsing would happen.
I think you can use function overloading here:
#include <iostream>
const char* str = "some random string";
void parse(const char* ch, size_t len)
{
while ( 1 ) {
if ( len == 0 ) {
std::cout << std::endl;
return ;
} else {
len--;
}
std::cout << *ch;
++ch;
/* the big part can be moved into separate function */
bigPart(ch);
}
}
void parse(const char* ch)
{
while ( 1 ) {
if ( !(*ch) ) {
std::cout << std::endl;
return ;
}
std::cout << *ch;
++ch;
/* the big part can be moved into separate function */
bigPart(ch);
}
}
int main()
{
parse(str, 5);
parse(str);
}
You can do this with a pair of overloads that delegate to a templated version to avoid duplicating code:
template <bool LengthOpt>
void do_parse(const char* ch, std::size_t len) {
// ...
}
void parse(const char* ch) {
do_parse<true>(ch, 0);
}
void parse(const char* ch, std::size_t len) {
do_parse<false>(ch, len);
}
Or you can switch to an iterator-based approach:
template<typename Iterator, typename Sentinel>
void do_parse(Iterator it, Sentinel end) {
for (; it != end; ++it) {
char c = *it;
// ...
}
}
struct null_sentinel_t {};
inline constexpr null_sentinel_t null_sentinel{};
inline constexpr bool operator==(null_sentinel_t, const char* p) noexcept { return *p == 0; }
// The next 3 overloads are not necessary in C++20
inline constexpr bool operator==(const char* p, null_sentinel_t) noexcept { return *p == 0; }
inline constexpr bool operator!=(null_sentinel_t, const char* p) noexcept { return *p != 0; }
inline constexpr bool operator!=(const char* p, null_sentinel_t) noexcept { return *p != 0; }
void parse(const char* ch) {
do_parse(ch, null_sentinel);
}
void parse(const char* ch, std::size_t len) {
do_parse(ch, ch + len);
}

How to initialize a char array MEMBER from a STRING LITERAL in a constexpr trough a CTOR

So this works:
template<size_t N>
struct LTxt
{
char txt[N];
};
void Test1()
{
//LTxt<10> fromliteral = "test1"; does not work, but ok
LTxt<10> fromlitera2 = { "test2" };
constexpr LTxt<10> fromliteral3 = { "test3" };
}
But the moment you write a constructor for that struct, you lose that auto "privilege".
Whats the constructor implementation I can write to keep that functionality.
I tried a lot of things:(the commented code doesnt work)
template<size_t N>
struct LTxt2
{
char txt[N];
//LTxt2() = default; // doesnt change anything
template<size_t N>
constexpr LTxt2(const char(&sz)[N])
//: txt{ sz } // Error C2075 array initialization requires a brace - enclosed initializer list
{
for (int c = 0; c < N; ++c) txt[c] = sz[c];
}
};
void Test2()
{
LTxt2<10> fromliteral = "test1";
//constexpr LTxt2<10> fromliteral2 = "test2";
LTxt2<10> fromliteral3 = { "test3" };
//constexpr LTxt2<10> fromliteral4 = { "test4" };
LTxt2<10> fromliteral5("test5");
//constexpr LTxt2<10> fromliteral6("test6");
LTxt2<10> fromliteral7({ "test7" });
//constexpr LTxt2<10> fromliteral8({ "test8" });
}
template<size_t N>
struct LTxt3
{
char txt[N];
constexpr LTxt3(std::initializer_list<char> list)
//:txt(list) {}
//:txt{ list }// {}
{
int c = 0;
for (auto p = list.begin(); p != list.end(); ++p, ++c)
txt[c] = *p;
}
};
void Test3()
{
//LTxt3<10> fromliteral = "test1";
//constexpr LTxt3<10> fromliteral2 = "test2";
//LTxt3<10> fromliteral3 = { "test3" }; //why in the name of fuck that doesnt work
//constexpr LTxt3<10> fromliteral4 = { "test4" };
//LTxt3<10> fromliteral5("test5");
//constexpr LTxt3<10> fromliteral6("test6");
//LTxt3<10> fromliteral7({ "test7" });
//constexpr LTxt3<10> fromliteral8({ "test8" });
LTxt3<10> fromliteral9 = { 't','e','s','t','9' };
//constexpr LTxt3<10> fromliteral10 = { 't','e','s','t','1', '0' };
}
template<size_t N>
struct LTxt4
{
char txt[N];
template<typename ... Params>
constexpr LTxt4(Params ... sz)
: txt{ sz... }
{}
};
void Test4()
{
//LTxt4<10> fromliteral = "test1";
//LTxt4<10> fromliteral = { "test1" };
//LTxt4<10> fromliteral { "test1" };
//LTxt4<10> fromliteral("test1");
LTxt4<10> fromliteral = { 't','e','s','t','1' };
constexpr LTxt4<10> fromliteral2 = { 't','e','s','t','2' };
}
I came up with this:
#include <iostream>
#include <stdexcept>
template<size_t N>
struct LTxt
{
char txt[N] {};
};
template <class Char, Char... Cs>
constexpr auto operator""_txt()
{
LTxt<sizeof...(Cs)> text;
size_t index = 0;
auto addChar = [&](char c)
{
text.txt[index] = c;
index++;
};
((addChar(Cs)), ...);
return text;
}
int main() {
constexpr auto txt = "test"_txt;
for (int i = 0 ; i < 4 ; i++)
{
std::cout << txt.txt[i] << std::endl;
}
}
Note: The string literal operator templates taking an argument pack of characters is an GNU extension and don't work with -pedantic-errors. Both clang and gcc support it.
I you want support the syntax:
std::cout << txt.txt << std::endl;
You need to add an '\0':
template <class Char, Char... Cs>
constexpr auto operator""_txt()
{
LTxt<sizeof...(Cs)+1> text;
size_t index = 0;
auto addChar = [&](char c)
{
text.txt[index] = c;
index++;
};
((addChar(Cs)), ...);
text.txt[index] = '\0';
return text;
}
Syntax:
((addChar(Cs)), ...); is an fold expression.
Before c++17 when can simulate it with this trick:
auto initializerList = {
(
addChar(Cs) // real code
, 0 // the expression is evaluated at 0 each time
)... // expand the parameter pack,
, 0 // if we do: ""_txt;
// we need at least one element for the auto deduction
};
(void) initializerList; // silence warning
It works because the parameter pack expansion :
expands to comma-separated list of zero or more patterns. Pattern must include at least one parameter pack.
So it will repeat the whole addChar(Cs),0 for each char in Cs.

Main function body doesn't detect call to overloaded variadic-templated function C++

I'm currently learning variadic template functions and parameter packing/unpacking.
This is my code,
template<typename T, typename U>
void my_insert(std::vector<int>& v, T& t) {
int i;
if (typeid(t).name() == typeid(const char*).name()) {
i = stoi(t);
}
else if (typeid(t).name() == typeid(char).name()) {
i = t - 48;
}
else if (typeid(t).name() == typeid(int).name()) {
i = t;
}
else if (typeid(t).name() == typeid(double).name()) {
i = static_cast<int>(round(t));
}
else if (typeid(t).name() == typeid(bool).name()) {
if (t) i == 1;
else i == 0;
}
else if (typeid(t).name() == typeid(std::vector<U>).name()) {
int j = 0;
while (j < t.size()) {
my_insert(v, t[j]);
++j;
}
}
else return;
v.push_back(i);
}
template<typename T, typename U, typename ...Args>
void my_insert(std::vector<int>& v, T& t, Args&... args) {
int i;
if (typeid(t).name() == typeid(const char*).name()) {
if (isdigit(t[0])) i = stoi(t);
// else do nothing
}
else if (typeid(t).name() == typeid(char).name()) {
i = t - 48;
}
else if (typeid(t).name() == typeid(int).name()) {
i = t;
}
else if (typeid(t).name() == typeid(double).name()) {
i = static_cast<int>(round(t));
}
else if (typeid(t).name() == typeid(bool).name()) {
if (t) i == 1;
else i == 0;
}
else if (typeid(t).name() == typeid(std::vector<U>).name()) {
int j = 0;
while (j < t.size()) {
my_insert(v, t[j]);
++j;
}
}
//else do nothing
v.push_back(i);
my_insert(args...);
}
int main() {
std::vector<int> v;
my_insert(v, "123", "-8", 32, 3.14159, true, true, false, '5', "12.3");
return 0;
}
ERROR : no instance of overloaded function my_insert matches the argument list
I don't understand what mistake I've made since for me the same exact implementation of the a print() function works with { cout << t << endl; print(args...); } , w/ signature <typename T, typename ...Args> void print(const T& t, const Args... args);
I know that a variadic function can be implemented with recursive calls non-variadic parameter overloaded versions of the same function. A so-called base case statement.
With all that being said, I'm unsure what it is that I'm doing incorrectly.
Well... there are some problems in your code.
The blocking error is the template parameter U
template<typename T, typename U>
void my_insert(std::vector<int>& v, T& t)
template<typename T, typename U, typename ...Args>
void my_insert(std::vector<int>& v, T& t, Args&... args)
The compiler can't deduce it and calling the function
my_insert(v, "123", "-8", 32, 3.14159, true, true, false, '5', "12.3");
the U isn't explicated
I suppose that the idea is "if T is a std::vector of some type U, add all element of the vector". If I understand correctly, I suggest to add a different overloaded version of the function.
Other problems...
1) In a couple of points you write something as
if (t) i == 1;
else i == 0;
It seems to me that your using operator == (comparison) instead of = (assignment).
General suggestion: enable the highest warning level to intercept this sort of trivial errors.
2) Your using typeid
if (typeid(t).name() == typeid(char).name())
to compare types.
Suggestion: use std::is_same instead
if ( std::is_same<T, char>::value )
3) The ground case of your recursion is a my_insert() function that is almost identical to the recursive version; the only differences are the absence of Args... argument and recursion call.
This is error prone because, if you modify one of the two version, you must remember to modify the other in the same way.
Suggestion: write a empty-and-do-nothing ground case; something as
void my_insert (std::vector<int> & v)
{ }
4) you can't compile
i = stoi(t);
when t isn't a char const *
Analogous problems with other assignments.
The problem is that when you write [pseudocode]
if ( condition )
statement_1;
else
statement_2;
the compiler must compile both statement_1 and statement_2 also when know compile-time that condition is true or false.
To avoid the compilation of the unused statement, you have to use if constexpr.
So you have to write something as
if constexpr ( std::is_same_v<T, char const *> )
i = std::stoi(t);
else if constexpr ( std::is_same_v<T, char> )
i = t - 48;
else if constexpr ( std::is_same_v<T, int> )
i = t;
else if constexpr ( std::is_same_v<T, double> )
i = static_cast<int>(std::round(t));
else if constexpr ( std::is_same_v<T, bool> )
i = t;
Unfortunately, if constexpr is available only starting from C++17.
Before C++17, you have to write different overloaded functions.
5) calling my_insert() recursively, you have to remember the v vector
my_insert(args...); // <-- wrong! no v
my_insert(v, args...); // <-- correct
6) take in count that "123" is convertible to char const * but isn't a char const * (it's a char const [4]); so, instead of
if constexpr ( std::is_same_v<T, char const *> )
i = std::stoi(t);
you can try with
if constexpr ( std::is_convertible_v<T, char const *> )
i = std::stoi(t);
The following is a possible C++17 implementation of your code
#include <cmath>
#include <string>
#include <vector>
#include <iostream>
void my_insert (std::vector<int> const &)
{ }
template <typename T, typename ... As>
void my_insert (std::vector<int> &, std::vector<T> const &, As const & ...);
template <typename T, typename ... As>
void my_insert (std::vector<int> & v, T const & t, As const & ... as)
{
int i{};
if constexpr ( std::is_convertible_v<T, char const *> )
i = std::stoi(t);
else if constexpr ( std::is_same_v<T, char> )
i = t - 48;
else if constexpr ( std::is_same_v<T, int> )
i = t;
else if constexpr ( std::is_same_v<T, double> )
i = static_cast<int>(std::round(t));
else if constexpr ( std::is_same_v<T, bool> )
i = t;
// else ???
v.push_back(i);
my_insert(v, as...);
}
template <typename T, typename ... As>
void my_insert (std::vector<int> & v, std::vector<T> const & t,
As const & ... as)
{
for ( auto const & val : t )
my_insert(v, val);
my_insert(v, as...);
}
int main ()
{
std::vector<int> v;
std::vector<char> u { '9', '8', '7' };
my_insert(v, "123", "-8", 32, 3.14159, true, u, false, '5', "12.3");
for ( auto const & val : v )
std::cout << val << ' ';
std::cout << std::endl;
}

Auto generating conditional expression from list/map

I am working on a program, that has to initialize many different objects according to a list that defines which type each object is.
The code that does this task looks like this:
// name is one entry of the type list
// itemList is a std::vector where the new items are appended
if(name == "foo")
{
initItem<FooObject>(itemList);
}
else if(name == "bar")
{
initItem<BarObject>(itemList);
}
else if(name == "baz")
{
initItem<Object3>(itemList);
}
....
initItem(ItemList) allocates an object of type T and appends it to itemList.
At other place in the code there are similar conditional statements for the different object types.
At the moment for each new object type added I have to add a new else if to all the conditional statements which is kind of annoying.
Is there a way to just define some kind of map somewhere that holds the assignment like
"foo", FooObject,
"bar", BarObject,
"baz", Object3,
and then template/auto-generate (maybe by preprocessor) the if-else statements so i don't have to setup them by hand every time?
Edit: Here is the whole method that contains the code snipset (there are many more else if() statements that all work according to the same principal.
bool Model::xml2Tree(const pugi::xml_node &xml_node, std::vector<TreeItem*> &parents)
{
bool all_ok = true;
bool sucess;
pugi::xml_node child_node = xml_node.first_child();
for (; child_node; child_node = child_node.next_sibling())
{
sucess = true;
bool ok = false;
std::string name = child_node.name();
if(name == "foo")
{
ok = initTreeItem<FooObject>(child_node, parents);
}
else if(name == "bar")
{
ok = initTreeItem<BarObject>(child_node, parents);
}
...
...
...
else
{
ok = false;
std::cout << "Unknown Element" << std::endl;
continue;
}
if(!sucess)
{
continue;
}
all_ok = all_ok && ok;
// recursiv
ok = xml2Tree(child_node, parents);
all_ok = all_ok && ok;
}
parents.pop_back();
return all_ok;
}
template<class T>
bool Model::initTreeItem(const pugi::xml_node &xml_node,
std::vector<TreeItem *> &parents)
{
bool ok = false;
T *pos = new T(parents.back());
parents.back()->appendChild(pos);
ok = pos->initFromXml(xml_node);
parents.push_back(pos);
return ok;
}
Firstly, you can encode your mapping in the type system as follows:
template <typename T>
struct type_wrapper { using type = T; };
template <typename T>
inline constexpr type_wrapper<T> t{};
template <typename K, typename V>
struct pair
{
K _k;
V _v;
constexpr pair(K k, V v) : _k{k}, _v{v} { }
};
template <typename... Ts>
struct map : Ts...
{
constexpr map(Ts... xs) : Ts{xs}... { }
};
constexpr auto my_map = map{
pair{[]{ return "foo"; }, t<FooObject>},
pair{[]{ return "bar"; }, t<BarObject>},
pair{[]{ return "baz"; }, t<Object3>}
};
We're using lambdas as they're implicitly constexpr in C++17, in order to simulate "constexpr arguments". If you do not require this, you can create a constexpr wrapper over a string literal and use that instead.
You can then go through the mapping with something like this:
template <typename... Pairs>
void for_kv_pairs(const std::string& name, map<Pairs...> m)
{
([&]<typename K, typename V>(const pair<K, V>& p)
{
if(name == p._k())
{
initItem<typename V::type>();
}
}(static_cast<const Pairs&>(m)), ...);
}
This is using a fold expression over the comma operator plus C++20 template syntax in lambdas. The latter can be replaced by providing an extra implementation function to retrieve K and V from pair pre-C++20.
Usage:
template <typename X>
void initItem()
{
std::cout << typeid(X).name() << '\n';
}
struct FooObject { };
struct BarObject { };
struct Object3 { };
constexpr auto my_map = map{
pair{[]{ return "foo"; }, t<FooObject>},
pair{[]{ return "bar"; }, t<BarObject>},
pair{[]{ return "baz"; }, t<Object3>}
};
int main()
{
for_kv_pairs("bar", my_map);
}
Output:
9BarObject
live example on wandbox.org
You can use higher-order macros (or x-macros) to generate code like that, for example:
#define each_item(item, sep) \
item("foo", FooObject) sep \
item("bar", BarObject) sep \
item("baz", Object3)
#define item_init(item_name, item_type) \
if (name == item_name) { \
initItem<item_type>(itemList); \
}
each_item(item_init, else)

Is it possible to define a variable that can be set only once?

I know of const, that can't be changed after creation. But I was wondering if there is a way to declare a variable that you set only once and after that, can't overwrite.
In my code, I would like to avoid the bool variable by having an nFirst that, once set to nIdx, can't be set to the new value of nIdx.
My code:
int nFirst = 0;
int nIdx = 0;
bool bFound = false;
BOOST_FOREACH(Foo* pFoo, aArray)
{
if (pFoo!= NULL)
{
pFoo->DoSmth();
if (!bFound)
{
nFirst= nIdx;
bFound = true;
}
}
nIdx++;
}
Pretty easy to roll your own.
template<typename T>
class SetOnce
{
public:
SetOnce(T init) : m_Val(init)
{}
SetOnce<T>& operator=(const T& other)
{
std::call_once(m_OnceFlag, [&]()
{
m_Val = other;
});
return *this;
}
const T& get() { return m_Val; }
private:
T m_Val;
std::once_flag m_OnceFlag;
};
Then just use the wrapper class for your variable.
SetOnce<int> nFirst(0);
nFirst= 1;
nFirst= 2;
nFirst= 3;
std::cout << nFirst.get() << std::endl;
Outputs:
1
I would like to avoid the bool variable
You can check nFirst itself, based on the fact that it won't be set a negative number. Such as:
int nFirst = -1;
int nIdx = 0;
BOOST_FOREACH(Foo* pFoo, aArray)
{
if (pFoo != NULL)
{
pFoo->DoSmth();
if (nFirst == -1)
{
nFirst = nIdx;
}
}
nIdx++;
}
Similar to cocarin's, but throws exception instead of silently ignoring assignment:
template <typename T, typename Counter = unsigned char>
class SetOnce {
public:
SetOnce(const T& initval = T(), const Counter& initcount = 1):
val(initval), counter(initcount) {}
SetOnce(const SetOnce&) = default;
SetOnce<T, Counter>& operator=(const T& newval) {
if (counter) {
--counter;
val = newval;
return *this;
}
else throw "Some error";
}
operator const T&() const { return val; } // "getter"
protected:
T val;
Counter counter;
};
Usage:
SetOnce<int> x = 42;
std::cout << x << '\n'; // => 42
x = 4;
// x = 5; // fails
std::cout << x << '\n'; // => 4
Online demo
Your question is about avoiding the bool but also implies the need for const-ness.
To avoid the bool, I'd use a boost::optional like this:
boost::optional<int> nFirst;
// ..
if (!nFirst) nFirst = nIdx;
// and now you can use *nFirst to get its value
Then, you can enforce logical (rather than literal) const-ness like this:
const boost::optional<int> nFirst;
// ..
if (!nFirst) const_cast<boost::optional<int>&>(nFirst) = nIdx;
// you can use *nFirst to get the value, any attempt to change it would cause a compile-time error
Using const_cast is not the safest practice, but in your particular case and as long as you only do it once it'd be OK. It simplifies both your code and your intentions: you do want a const, it's just that you want to defer it's initialisation for a bit.
Now, as songyuanyao suggested, you could directly use an int instead of a boost::optional, but the latter makes your intention explicit so I think it's better this way. In the end of day this is C++ while songyuanyao's solution is really a C-style one.
This is set once template. You can use this class as assurance that the value will be set and saved only once. Every next try will be canceled.
#include <iostream>
using namespace std;
template <class T>
class SetOnce;
template<class T>
std::ostream& operator<<( ostream& os, const SetOnce<T>& Obj );
template <class T>
class SetOnce
{
public:
SetOnce() {set = false; }
~SetOnce() {}
void SetValue(T newValue) { value = !set ? newValue : value; set = true; }
private:
T value;
bool set;
friend std::ostream& operator<< <>( ostream& os, const SetOnce& Obj );
public:
SetOnce<T>& operator=( const T& newValue )
{
this->SetValue(newValue);
return *this;
}
};
template<class T>
std::ostream& operator<<( ostream& os, const SetOnce<T>& Obj )
{
os << Obj.value;
return os;
}
Use case:
int main()
{
SetOnce<bool> bvar;
SetOnce<int> ivar;
SetOnce<std::string> strvar;
std::cout<<"initial values: \n"<<bvar<<" "
<<ivar<<" "<<strvar<<" \n\n";
bvar = false; //bvar.SetValue(false);
ivar = 45; //ivar.SetValue(45);
strvar = "Darth Vader"; //strvar.SetValue("Darth Vader");
std::cout<<"set values: \n"<<bvar<<" "
<<ivar<<" "<<strvar<<" \n\n";
bvar = true; //bvar.SetValue(true);
ivar = 0; //ivar.SetValue(0);
strvar = "Anakin"; //strvar.SetValue("Anakin");
std::cout<<"set again values: \n"<<bvar<<" "
<<ivar<<" "<<strvar<<" \n\n";
return 0;
}