Reputation: 1804
I wanted to make a class that will verify the finding of several strings or char const *'s.. I expected since "something" is constant it will work, or even if I declared it as a static const parameter.. unfortunately that did not work.. anyone sees anything wrong with that class?
template<char const*... Args_t>
struct Finder {
Finder() {
Add<Args_t...>();
m_len = sizeof...(Args_t);
m_count = 0;
}
void Append(char const* key, string val) {
Found_t::iterator found = m_founds.find(key);
if (key == m_founds.end()) return; // irrelevant
if (!found->second.empty()) {
stringstream str;
str << "Found an already existing key: [" << key << ']' << endl;
throw logic_error(str.str());
}
found ->second = std::move(val);
++m_count;
}
bool Complete() { return m_len == m_count; }
private:
template<char const* First_t, char const*... Rest_t> void Add() {
m_founds.insert(Found_t::value_type(First_t, ""));
Add<Rest_t...>();
}
template<char const* Last_t> void Add() {
m_founds.insert(Found_t::value_type(Last_t, ""));
}
typedef std::map<char const*, string> Found_t;
Found_t m_founds;
int m_len;
int m_count;
};
and then in the main I tried something like:
Finder<"firstStr", "secondStr"> finder;
Or
static const char const* s_first = "first";
static const char const* s_second = "second";
Finder<s_first, s_second> finder;
The error I am getting is: expression must have a constant value
Upvotes: 0
Views: 1562
Reputation: 35901
Non-type template parameters must obey some rules, basically it must be unique (having external linkage used to be one of them, but as Constructor points out in the comment this is no longer exactly tru) - relevant part of the standard:
a constant expression ( 5.19 ) that designates the address of an object with static storage duration and external or internal linkage or a function with external or internal linkage, including function templates and function template-id s but excluding non-static class members, expressed (ignoring parentheses) as & id-expression , except that the & may be omitted if the name refers to a function or array and shall be omitted if the corresponding template-parameter is a reference
Both example usages you show do not match, these are ok on the other hand:
extern const char s_first[] = "first";
static constexpr char s_second[] = "second";
Finder< s_first, s_second > f;
edit
your sample has a couple of other problems (ambiguous definition of Add
, comparing key
with m_founds.end()
, proper version by Jarod42:
template<char const*... Args_t>
struct Finder {
Finder() {
Add<Args_t...>();
m_len = sizeof...(Args_t);
m_count = 0;
}
void Append(char const* key, string val) {
Found_t::iterator found = m_founds.find(key);
if (found == m_founds.end()) return; // irrelevant
if (!found->second.empty()) {
stringstream str;
str << "Found an already existing key: [" << key << ']' << endl;
throw logic_error(str.str());
}
found ->second = std::move(val);
++m_count;
}
bool Complete() { return m_len == m_count; }
private:
template<char const* First_t, char const* Second_t, char const*... Rest_t> void Add() {
m_founds.insert(Found_t::value_type(First_t, ""));
Add<Second_t, Rest_t...>();
}
template<char const* Last_t> void Add() {
m_founds.insert(Found_t::value_type(Last_t, ""));
}
typedef std::map<char const*, string> Found_t;
Found_t m_founds;
int m_len;
int m_count;
};
Upvotes: 3