Home > Mobile >  Concept and templates no longer run with g -11
Concept and templates no longer run with g -11

Time:08-13

The following code :

#include <cstdio>
#include <string>
#include <concepts>
template<typename T,  typename KEY, typename JSON_VALUE, typename...KEYS>
concept json_concept = requires(T t, int index, std::string& json_body, KEY key, JSON_VALUE value, KEYS... keys)
{ 
    { t.template get_value<T>(keys...) } -> std::same_as<T>;
    { t.template get_value<T>(key) } -> std::same_as<T>;
    { t.template get_value<T>(index, keys...) } -> std::same_as<T>;

    { t.set_cache(keys...) } -> std::same_as<void>;
    { t.get_list_size() } -> std::same_as<int>;
    { t.init_cache() } -> std::same_as<void>;
    { t.load(json_body) } -> std::same_as<void>;
    { t.contains(key) } -> std::same_as<bool>;

    { t.set_root_value(value) } -> std::same_as<void>;
    { t.release() } -> std::same_as<JSON_VALUE>;


};


class JsonUtil {
public:

    template<json_concept JSON_OPERATOR>
    JsonUtil(std::string body, JSON_OPERATOR& json_impl) {
        json_impl.load(body);
    }
    
       template<typename T, json_concept JSON_OPERATOR, typename KEY>
    T get_value(JSON_OPERATOR& json_impl, KEY&&  key) {
        return json_impl.template get_value<T>(std::forward<KEY>(key));
    }


    template<typename T, json_concept JSON_OPERATOR, typename... KEYS>
    T get_value(JSON_OPERATOR& json_impl, KEYS&& ... keys) {
        return json_impl.template get_value<T>(std::forward<KEYS>(keys)...);
    }

    template<json_concept JSON_OPERATOR, typename... KEYS>
    void set_cache(JSON_OPERATOR& json_impl, KEYS&& ... keys) {
        json_impl.set_cache(std::forward<KEYS>(keys)...);
    }

    template<json_concept JSON_OPERATOR>
    void init_cache(JSON_OPERATOR& json_impl) {
        json_impl.init_cache();
    }
};



class IJson {
public:
  template<typename T, typename KEY>
    T get_value(KEY&& key) {
      
      return T();
      }
  
  void load(std::string body) { };
};

int main()
{
  IJson dd = IJson{};
        JsonUtil jsoncpp(std::string("dummy"), dd);

}

This code used to run with clang -10. When I started using g -11 it fails to compile with following error:

conc.cpp:26:14: error: wrong number of template arguments (1, should be at least 3)
   26 |     template<json_concept JSON_OPERATOR>
      |              ^~~~~~~~~~~~~~~~~~~
conc.cpp:4:9: note: provided for ‘template<class T, class ... KEYS, class KEY, class JSON_VALUE> concept json_concept’
    4 | concept json_concept = requires(T t, int index, std::string& json_body, KEYS... keys, KEY key, JSON_VALUE value)

What is the problem and how do I solve it please. Is the solution really to provide all templates types each time I invoke a function part of the concept even though not all template argument would be used?

The g version is 11.1.0

CodePudding user response:

You are not using concepts with template parameters correctly. Clang is totally wrong in accepting your code. Its support for concepts doesn't seem to be mature enough.

If you have:

template <typename A, typename B, typename C>
concept foo = ...

then the correct usage of foo is with two template type arguments:

template <foo<int, char> Z> class bar ...
template <typename X, foo<X,X> Z> class baz...

Otherwise the concept has no idea what B and C are.

See this passage in the draft standard.

For this reason you cannot have a template parameter pack in the middle of the concept. Move it to the end:

template<typename T, typename KEY, typename JSON_VALUE, typename...KEYS>
concept json_concept = ...

Then something like this should work:

template<typename K, typename V, typename ... Ks, 
         json_concept<K, V, Ks> JSON_OPERATOR>
JsonUtil(std::string body, JSON_OPERATOR& json_impl) {
    json_impl.load(body);
}

But this is just the beginning of the problem.

You write

t.template get_value<T>(key)

but this makes no sense. T is the name of the type that satisfies json_concept, in your example IJson. So you are passing IJson as the template parameter of IJson::get_value<IJson>. This is not how get_value is supposed to be used. You should be using something like

value = t.template get_value<JSON_VALUE>(key);

It is unclear what the other two overloads of get_value correspond to in IJson. IJson cannot satisfy json_concepts with all the requirements, whatever syntax you use to express them. It simply doesn't have all the required overloads.

It is also unclear how one can have such a parameterized concept where only part of the parameters participate in some requirements. Consider this:

template<json_concept JSON_OPERATOR<???>>
JsonUtil(std::string body, JSON_OPERATOR& json_impl) {
    json_impl.load(body);
}

The concept requires you to provide key, keys, and value, but none of those is used in load and there is no good way to provide them in this context. You could use some defaults but this is sweeping the dirt under the rug.

  • Related