Default template arguments when using template template parameters - c++

The following code compiles using gcc 5.2, gcc 4.9, and clang 3.7 at C++11 standard:
template <typename T, typename U, template<typename...> class M>
U * find_item(M<T, U> & m, const T & t) {
auto it = m.find(t);
if (it != m.end()) { return &it->second; }
return nullptr;
}
template <typename T, typename U, template<typename...> class M>
const U * find_item(const M<T, U> & m, const T & t) {
auto it = m.find(t);
if (it != m.end()) { return &it->second; }
return nullptr;
}
#include <map>
#include <unordered_map>
#include <string>
#include <iostream>
int main() {
std::map<std::string, int> foo;
foo["asdf"] = 5;
if (find_item(foo, std::string{"bar"})) { std::cerr << "hmm\n"; }
}
However, when I compile it with the latest version of emscripten, I get a compiler error stemming from too few arguments for class template 'map':
main.cpp:24:7: error: no matching function for call to 'find_item'
if (find_item(foo, std::string{"bar"})) { std::cerr << "hmm\n"; }
^~~~~~~~~
main.cpp:2:5: note: candidate template ignored: substitution failure [with T =
std::__1::basic_string<char>, U = int, M = map]: too few template
arguments for class template 'map'
U * find_item(M<T, U> & m, const T & t) {
^ ~
main.cpp:9:11: note: candidate template ignored: substitution failure [with T =
std::__1::basic_string<char>, U = int, M = map]: too few template
arguments for class template 'map'
const U * find_item(const M<T, U> & m, const T & t) {
^ ~
1 error generated.
ERROR:root:compiler frontend failed to generate LLVM bitcode, halting
This is a bit odd because my emscripten claims to be based on clang-3.7. Regardless, it seems to have difficulty deducing the default parameters while instantiating the find_item template.
If the code is changed in the following way, then all compilers seem to be happy with it:
template <typename T, typename U, template<typename...> class M, typename... dummy>
U * find_item(M<T, U, dummy...> & m, const T & t) {
auto it = m.find(t);
if (it != m.end()) { return &it->second; }
return nullptr;
}
template <typename T, typename U, template<typename...> class M, typename... dummy>
const U * find_item(const M<T, U, dummy...> & m, const T & t) {
auto it = m.find(t);
if (it != m.end()) { return &it->second; }
return nullptr;
}
#include <map>
#include <unordered_map>
#include <string>
#include <iostream>
int main() {
std::map<std::string, int> foo;
foo["asdf"] = 5;
if (find_item(foo, std::string{"bar"})) { std::cerr << "hmm\n"; }
}
The question is, should the "dummy" part actually be necessary according to the C++11 standard, or is emscripten defective in not figuring out the default template parameters here?
My reading of section [temp.deduct.type] 14.8.2.6.8 is that it should be able to bind std::map to a template template parameter of the form M<T, U> because of the wording "at least one" in this sentence:
Similarly, <T> represents template argument
lists where at least one argument contains a T
But, I'm not sure about that.

I hit this problem and found that I didn't need the dummy template parameter, specifying the template template as variadic was enough (this is on clang 3.6):
template <typename T, typename U, template<typename...> class M>
U * find_item(M<T, U> & m, const T & t) {
auto it = m.find(t);
if (it != m.end()) { return &it->second; }
return nullptr;
}
template <typename T, typename U, template<typename...> class M>
const U * find_item(const M<T, U> & m, const T & t) {
auto it = m.find(t);
if (it != m.end()) { return &it->second; }
return nullptr;
}

Related

SFINAE: 'enable_if' cannot be used to disable this declaration

I want to enable and disable a function declaration in a template class, just based on if the template parameter has one type defined or not for which I use boost/tti/has_type.hpp. However, I got the complains from compiler, i.e., 'enable_if' cannot be used to disable this declaration.
#include <boost/tti/has_type.hpp>
#include <iostream>
#include <vector>
#include <set>
using namespace std;
BOOST_TTI_HAS_TYPE(key_type)
template <typename container>
class adapter : public container
{
public:
using container::container;
public:
template <typename type = typename enable_if<!has_type_key_type<container>::value,typename container::value_type>::type>
bool contains(typename container::value_type const & v) { return find(begin(*this),end(*this),v) != end(*this); }
template <typename type = typename enable_if<has_type_key_type<container>::value,typename container::value_type>::type>
bool contains(typename container::key_type const & k) { return this->find(k) != this->end(); }
};
int main()
{
cout << has_type_key_type<adapter<vector<int>>>::value << endl;
cout << has_type_key_type<adapter<set<int>>>::value << endl;
}
How could I resolve it? However, if I change it to similar non-member function template, it works.
#include <boost/tti/has_type.hpp>
#include <iostream>
#include <vector>
#include <set>
using namespace std;
BOOST_TTI_HAS_TYPE(key_type)
template <typename container, typename enable_if<!has_type_key_type<container>::value,int>::type = 0>
bool contains(container const & c, typename container::value_type const & v) { return find(begin(c),end(c),v) != end(c); }
template <typename container, typename enable_if<has_type_key_type<container>::value,int>::type = 0>
bool contains(container const & c, typename container::key_type const & k) { return c.find(k) != c.end(); }
template <typename container>
class adapter : public container
{
public:
using container::container;
public:
// ...
};
int main()
{
vector<double> v{3.14};
set<double> s{2.71};
cout << contains(v,3.14) << endl;
cout << contains(s,2.71) << endl;
}
if I change it to similar non-member function template, it works.
The point is: funtion template.
Your code doesn't works because SFINAE works over templates, with test related to the template parameter. Your contains() method is a function, inside a template class, but isn't a template function.
To make SFINAE works for contains(), you have to transform it in a template function.
You have seen that works outside the class, but works also inside the class.
For example, with the following trick (caution: code not tested)
// .......VVVVVVVVVVVVVVVVVVVVVV
template <typename C = container, // ................V
typename std::enable_if<!has_type_key_type<C>::value, int>::type = 0>
bool contains (typename container::value_type const & v)
{ return find(begin(*this),end(*this),v) != end(*this); }
// .......VVVVVVVVVVVVVVVVVVVVVV
template <typename C = container, // ...............V
typename std::enable_if<has_type_key_type<C>::value, int>::type = 0>
bool contains (typename container::key_type const & k)
{ return this->find(k) != this->end(); }
Observe that the SFINAE test (has_type_key_type<C>::value) now involve C, the function's template parameter, not container, the template parameter of the class.
If you want avoid that constains() can be "hijacked" (explicitly setting a type for C, different from container, you can add a variadic non-type (and unused) template parameter.
For example
// .......VVVVVV
template <int..., typename C = container,
typename std::enable_if<!has_type_key_type<C>::value, int>::type = 0>
bool contains (typename container::value_type const & v)
{ return find(begin(*this),end(*this),v) != end(*this); }
// .......VVVVVV
template <int..., typename C = container,
typename std::enable_if<has_type_key_type<C>::value, int>::type = 0>
bool contains (typename container::key_type const & k)
{ return this->find(k) != this->end(); }
Off Topic: you you can use at least C++14, you ca use std::enable_if_t, so
std::enable_if_t<has_type_key_type<C>::value, int> = 0
instead of
typename std::enable_if<has_type_key_type<C>::value, int>::type = 0

Template function to extract value out of several nested unordered_map's

Let's assume I have a nested std::unordered_map that looks like this:
std::unordered_map<ResourceName, std::unordered_map<HAL::ResourceFormat::Color, HAL::RTDescriptor>>
I want a function that will return a pointer to HAL::RTDescriptor based on two keys ResourceName and HAL::ResourceFormat::Color if object is present or nullptr otherwise. The straightforward implementation looks like this:
const HAL::RTDescriptor* ResourceDescriptorStorage::GetRTDescriptor(ResourceName resourceName, HAL::ResourceFormat::Color format) const
{
auto mapIt = mRTDescriptorMap.find(resourceName);
if (mapIt == mRTDescriptorMap.end()) {
return nullptr;
}
auto& nestedMap = mapIt->second;
auto nestedMapIt = nestedMap.find(format);
if (nestedMapIt == nestedMap.end()) {
return nullptr;
}
return &nestedMapIt->second;
}
Is there a way to use templates to generalize the logic?
Something with parameter packs for keys. Something that will go through each nested container, check for object availability and return it or nullptr at the end:
template<
template<class...> class AssociativeContainer,
class... Keys
>
decltype(auto) Find(const AssociativeContainer<...>& rootContainer, Keys&&... keys)
{
...
}
Simpler solution (requires C++17):
template<class AssociativeContainer, class Key, class... Keys>
auto Find(const AssociativeContainer& container, Key&& key, Keys&&... keys){
auto it = container.find(std::forward<Key>(key));
bool found = it != container.end();
if constexpr(sizeof...(Keys) == 0)
return found ? &it->second : nullptr;
else
return found ? Find(it->second, std::forward<Keys>(keys)...) : nullptr;
}
This also allows to get a reference to any inbetween container, as it doesn't require to pass all keys.
Is there a way to use templates to generalize the logic? Something with parameter packs for keys. Something that will go through each nested container, check for object availability and return it or nullptr at the end:
Require a little of work (maybe someone more expert than me can make it simpler) but sure it's possible.
By example... given a custom type traits (and using to simplify the use) as follows
template <typename T>
struct lastType
{ using type = T; };
template <template <typename...> class C, typename K, typename V>
struct lastType<C<K, V>> : public lastType<V>
{ };
template <typename T>
using lastType_t = typename lastType<T>::type;
you can write Find() recursively as follows
// ground case
template <typename V>
V const * Find (V const & val)
{ return &val; }
// recursion case
template <typename C, typename K0, typename ... Ks>
lastType_t<C> const * Find (C const & cnt, K0 && key0, Ks && ... keys)
{
auto mapIt = cnt.find(std::forward<K0>(key0));
if ( mapIt == cnt.cend() )
return nullptr;
return Find(mapIt->second, std::forward<Ks>(keys)...);
}
The following is a full compiling example
#include <map>
#include <string>
#include <iostream>
#include <unordered_map>
template <typename T>
struct lastType
{ using type = T; };
template <template <typename...> class C, typename K, typename V>
struct lastType<C<K, V>> : public lastType<V>
{ };
template <typename T>
using lastType_t = typename lastType<T>::type;
template <typename V>
V const * Find (V const & val)
{ return &val; }
template <typename C, typename K0, typename ... Ks>
lastType_t<C> const * Find (C const & cnt, K0 && key0, Ks && ... keys)
{
auto mapIt = cnt.find(std::forward<K0>(key0));
if ( mapIt == cnt.cend() )
return nullptr;
return Find(mapIt->second, std::forward<Ks>(keys)...);
}
using typeC = std::map<int,
std::unordered_map<std::string,
std::unordered_map<long,
std::map<char, long long>>>>;
int main ()
{
typeC c;
c[0]["one"][2l]['3'] = 4ll;
auto v = Find(c, 0, "one", 2l, '3');
std::cout << (*v) << std::endl;
static_assert( std::is_same_v<decltype(v), long long const *>, "!" );
}
-- EDIT --
I'm particularly dumb today: as highlighted by krisz in his answer (thanks), the ternary operator permit the use of auto as return type (from C++14).
So there is no needs of the lastType custom type traits and Find() can be simply written as
// ground case
template <typename V>
V const * Find (V const & val)
{ return &val; }
// recursion case
template <typename C, typename K0, typename ... Ks>
auto Find (C const & cnt, K0 && key0, Ks && ... keys)
{
auto mapIt = cnt.find(std::forward<K0>(key0));
return mapIt == cnt.cend()
? nullptr
: Find(mapIt->second, std::forward<Ks>(keys)...);
}
For C++11, the recursion case require also the trailing return type; by example
-> decltype(Find(cnt.find(std::forward<K0>(key0))->second, std::forward<Ks>(keys)...))

C++ constexpr list with size in its type

I am trying to develop a constexpr, functional list data structure in C++. I am also trying to take advantage of recursive structure of the cons list approach. I had couple of attempts and for those, you can see my past questions. For now, I have settled on to the idea of making the size a part of type, ie. `List. Here is the code:
#include <iostream>
#include <type_traits>
template <typename T, unsigned int N>
struct list {
public:
constexpr list(const T& head, const list<T, N-1> &tail)
:_length{N}, _head{head}, _tail{tail}
{}
const unsigned int _length;
const T _head;
const list<T, N-1> _tail;
};
template <typename T, unsigned int N>
constexpr auto head(const list<T, N> &li) {
return li._head;
}
template <typename T, unsigned int N>
constexpr auto tail(const list<T, N> &li) {
return li._tail;
}
template <typename T, unsigned int N>
constexpr auto prepend(const T &new_head, const list<T, N> &li){
return list<T, N + 1>{new_head,
list<T, N>{head(li), tail(li)}};
}
template <typename T>
struct list<T, 0>
{
constexpr static const bool nil = true;
};
template <typename T>
using nil = list<T, 0>;
template <typename Functor, typename T, unsigned int N>
constexpr auto fmap(Functor f, const list<T, N> &li) {
if constexpr(N == 0)
return nil<T>{};
else
return list{f(head(li)), fmap(f, tail(li))};
}
template <typename T, unsigned int N>
std::ostream& operator<<(std::ostream& str, const list<T, N> &li) {
if constexpr(N == 0)
return str;
else{
str << head(li) << ' ' << tail(li);
return str;
}
}
int main(){
constexpr auto f = [](int x){ return x * x; };
constexpr list<char, 2> p2{'U', list<char, 1>{'S', nil<char>{}}};
constexpr auto p3 = prepend('S', p2);
constexpr list<int, 2> i1{1, list<int, 1>{2, nil<int>{}}};
constexpr auto i2 = fmap(f, i1);
std::cout << p3;
}
Some of it works to some extent. fmap is the one keeping my program from compiling. I get the error
prog.cc:47:16: error: no viable constructor or deduction guide for deduction of template arguments of 'list'
return list{f(head(li)), fmap(f, tail(li))};
prog.cc:47:34: note: in instantiation of function template specialization 'fmap<(lambda at prog.cc:61:24), int, 1>' requested here
return list{f(head(li)), fmap(f, tail(li))};
prog.cc:67:25: note: in instantiation of function template specialization 'fmap<(lambda at prog.cc:61:24), int, 2>' requested here
constexpr auto i2 = fmap(f, i1);
prog.cc:8:15: note: candidate template ignored: couldn't infer template argument 'N'
constexpr list(const T& head, const list &tail)
and similar. I am lost here, what is the cause of this error? It seems like compiler deduced the argument N correctly, as it says N=2. I feel like I need to add some base cases related to lists of size zero but could not figure it out.
You have a typo: missing type specifiers when using template struct list. Bellow should work
template <typename Functor, typename T, unsigned int N>
constexpr auto fmap(Functor f, const list<T, N> &li) {
if constexpr(N == 0)
return nil<T>{};
else
return list<T, N-1>{f(head(li)), fmap(f, tail(li))};
}

SFINAE failing when evaluating a constexpr in a template parameter?

For some reason, this constexpr is not being evaluated correctly in a template parameter context:
#include <iostream>
#include <functional>
namespace detail
{
// Reason to use an enum class rahter than just an int is so as to ensure
// there will not be any clashes resulting in an ambigious overload.
enum class enabler
{
enabled
};
}
#define ENABLE_IF(...) std::enable_if_t<(__VA_ARGS__), detail::enabler> = detail::enabler::enabled
#define ENABLE_IF_DEFINITION(...) std::enable_if_t<(__VA_ARGS__), detail::enabler>
namespace detail
{
template <typename T, bool IS_BUILTIN>
class is_value
{
T item_to_find;
std::function<bool(T const& lhs, T const& rhs)> predicate;
public:
constexpr is_value(T item_to_find, std::function<bool(T, T)> predicate)
: item_to_find(item_to_find)
, predicate(predicate)
{}
constexpr bool one_of() const
{
return false;
}
template <typename T1, typename...Ts>
constexpr bool one_of(T1 const & item, Ts const&...args) const
{
return predicate(item_to_find, item) ? true : one_of(args...);
}
};
template <typename T>
class is_value<T, false>
{
T const& item_to_find;
std::function<bool(T const& lhs, T const& rhs)> predicate;
public:
constexpr is_value(T const& item_to_find, std::function<bool(T const&, T const&)> predicate)
: item_to_find(item_to_find)
, predicate(predicate)
{}
constexpr bool one_of() const
{
return false;
}
template <typename T1, typename...Ts>
constexpr bool one_of(T1 const & item, Ts const&...args) const
{
return predicate(item_to_find, item) ? true : one_of(args...);
}
};
}
// Find if a value is one of one of the values in the variadic parameter list.
// There is one overload for builtin types and one for classes. This is so
// that you can use builtins for template parameters.
//
// Complexity is O(n).
//
// Usage:
//
// if (is_value(1).one_of(3, 2, 1)) { /* do something */ }
//
template <typename T, ENABLE_IF(!std::is_class<T>::value)>
constexpr auto const is_value(T item_to_find, std::function<bool(T, T)> predicate = [](T lhs, T rhs) { return lhs == rhs; })
{
return detail::is_value<T, true>(item_to_find, predicate);
}
template <typename T, ENABLE_IF(std::is_class<T>::value)>
constexpr auto const is_value(T const& item_to_find, std::function<bool(T const&, T const&)> predicate = [](T const& lhs, T const& rhs) { return lhs == rhs; })
{
return detail::is_value<T, false>(item_to_find, predicate);
}
template <int I, ENABLE_IF(is_value(I).one_of(3,2,1))>
void fn()
{
}
int main()
{
fn<3>();
std::cout << "Hello, world!\n" << is_value(3).one_of(3,2,1);
}
I've tested this with clang, g++ and vc++. Each had different errors:
clang
source_file.cpp:98:5: error: no matching function for call to 'fn'
fn<3>();
^~~~~
source_file.cpp:92:10: note: candidate template ignored: substitution failure [with I = 3]: non-type template argument is not a constant expression
void fn()
^
1 error generated.
g++
source_file.cpp: In function ‘int main()’:
source_file.cpp:98:11: error: no matching function for call to ‘fn()’
fn<3>();
...
vc++
source_file.cpp(91): fatal error C1001: An internal error has occurred in the compiler.
(compiler file 'msc1.cpp', line 1421)
...
Is my code invalid or are the compilers just not up to the job yet?
Your code is invalid. The compiler (GCC7.1 for me) provides helpful error that allows us to solve this problem.
Issue:
...\main.cpp|19|note: 'detail::is_value<int, true>' is not literal because:|
...\main.cpp|19|note: 'detail::is_value<int, true>' has a non-trivial destructor|
The reason detail::is_value does not have a trivial destructor is due to the std::function<> member; std::function<> might perform dynamic memory allocation (among other reasons), thus it is not trivial. You have to replace it with a trivially destructible type; I present a simple solution below.
Note: Even if std::function<> was trivially destructible, its operator() does not seem to be declared as constexpr (see: http://en.cppreference.com/w/cpp/utility/functional/function/operator()), so it would not work either.
Sample working code (adapt as needed):
#include <iostream>
#include <functional>
namespace detail
{
// Reason to use an enum class rahter than just an int is so as to ensure
// there will not be any clashes resulting in an ambigious overload.
enum class enabler
{
enabled
};
}
#define ENABLE_IF(...) std::enable_if_t<(__VA_ARGS__), detail::enabler> = detail::enabler::enabled
#define ENABLE_IF_DEFINITION(...) std::enable_if_t<(__VA_ARGS__), detail::enabler>
namespace detail
{
// notice the new template parameter F
template <typename T, typename F, bool IS_BUILTIN>
class is_value
{
T item_to_find;
F predicate;
public:
constexpr is_value(T item_to_find, F predicate)
: item_to_find(item_to_find)
, predicate(predicate)
{}
constexpr bool one_of() const
{
return false;
}
template <typename T1, typename...Ts>
constexpr bool one_of(T1 const & item, Ts const&...args) const
{
return predicate(item_to_find, item) ? true : one_of(args...);
}
};
template <typename T, typename F>
class is_value<T, F, false>
{
T const& item_to_find;
F predicate;
public:
constexpr is_value(T const& item_to_find, F predicate)
: item_to_find(item_to_find)
, predicate(predicate)
{}
constexpr bool one_of() const
{
return false;
}
template <typename T1, typename...Ts>
constexpr bool one_of(T1 const& item, Ts const&... args) const
{
return predicate(item_to_find, item) ? true : one_of(args...);
}
};
}
// sample predicate
template<class T>
struct default_compare
{
constexpr bool operator()(T const& lhs, T const& rhs) const
noexcept(noexcept(std::declval<T const&>() == std::declval<T const&>()))
{
return lhs == rhs;
}
};
// Find if a value is one of one of the values in the variadic parameter list.
// There is one overload for builtin types and one for classes. This is so
// that you can use builtins for template parameters.
//
// Complexity is O(n).
//
// Usage:
//
// if (is_value(1).one_of(3, 2, 1)) { /* do something */ }
//
template <typename T, typename F = default_compare<T>, ENABLE_IF(!std::is_class<T>::value)>
constexpr auto const is_value(T item_to_find, F predicate = {})
{
return detail::is_value<T, F, true>(item_to_find, predicate);
}
template <typename T, typename F = default_compare<T>, ENABLE_IF(std::is_class<T>::value)>
constexpr auto const is_value(T const& item_to_find, F predicate = {})
{
return detail::is_value<T, F, false>(item_to_find, predicate);
}
template <int I, ENABLE_IF(is_value(I).one_of(3,2,1))>
void fn()
{
}
int main()
{
fn<3>();
std::cout << "Hello, world!\n" << is_value(3).one_of(3,2,1);
}

Defining hash for vectors: template parameters not deducible in partial specialization

I am trying to define a hasher for vectors. I have a primary template for simple types, and a specialization for classes which have operator().
However, I get an error template parameters not deducible in partial specialization. Could somebody please point out why?
template <typename T> struct hash<vector<T>>
{
size_t operator()(const vector<T> &x) const
{
size_t res = 0;
for(const auto &v:x) {
boost::hash_combine(res,v);
}
return res;
}
};
template <typename T> struct hash<vector<enable_if_t<true_t<decltype(sizeof(declval<T>()()))>::value, T>>>
{
size_t operator()(const vector<T> &x) const
{
size_t res = 0;
for(const auto &v:x) {
boost::hash_combine(res,v());
}
return res;
}
};
I don't really like partial specialization here, especially as it causes code duplication.
template <typename T>
struct hash<vector<T>>
{
template<class T>
static auto call_if_possible(const T& t, int) -> decltype(t()) { return t(); }
template<class T>
static auto call_if_possible(const T& t, ...) -> decltype(t) { return t; }
size_t operator()(const vector<T> &x) const
{
size_t res = 0;
for(const auto &v:x) {
boost::hash_combine(res,call_if_possible(v, 0));
}
return res;
}
};
(If this hash is actually std::hash, then the answer is "don't do it". You may not specialize a standard library template unless the specialization depends on a user-defined type.)
In your second template specialization T inside the enable_if is in a non-deduced context, so the compiler cannot deduce it. It is effectively the same as:
template<typename T>
struct Identity
{
using type = T;
}
template<typename T>
void f(typename Identity<T>::type x){} // T is non-deducible
Moreover, you have a "double" non-deducible context, because an expression containing T inside a decltype is non-deducible.
for what it's worth, here was my first attempt - handles ADL-lookup of hash_value as well as the one in the boost namespace:
#include <iostream>
#include <boost/functional/hash.hpp>
#include <vector>
template<class T>
struct hash_value_defined
{
template<class U> static auto boost_hash_value_test(U*p) -> decltype(boost::hash_value(*p),
void(),
std::true_type());
template<class U> static auto adl_hash_value_test(U*p) -> decltype(hash_value(*p),
void(),
std::true_type());
template<class U> static std::false_type boost_hash_value_test(...);
template<class U> static std::false_type adl_hash_value_test(...);
static constexpr bool boost_value = decltype(boost_hash_value_test<T>(nullptr))::value;
static constexpr bool adl_value = decltype(adl_hash_value_test<T>(nullptr))::value;
static constexpr bool value = boost_value or adl_value;
};
template<class T, class A, std::enable_if_t<hash_value_defined<T>::value> * = nullptr >
size_t hash_value(const std::vector<T, A>& v) {
size_t seed = 0;
for(const auto& e : v) {
boost::hash_combine(seed, e);
}
return seed;
}
int main()
{
using namespace std;
vector<int> x { 1, 2, 3, 4, 5 };
auto h = hash_value(x);
cout << h << endl;
return 0;
}