将字符串文字作为非类型参数传递给类模板

发布于 2024-08-16 23:49:35 字数 113 浏览 23 评论 0 原文

我想声明一个类模板,其中模板参数之一采用字符串文字,例如 my_class<"string">

谁能给我一些可编译的代码,它声明了一个简单的类模板,如上所述?

I want to declare a class template in which one of the template parameters takes a string literal, e.g. my_class<"string">.

Can anyone give me some compilable code which declares a simple class template as described?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(17

与君绝 2024-08-23 23:49:35

可以有一个const char*非类型模板参数,并向其传递一个带有staticconst char[]变量code> 链接,这与直接传递字符串文字相差不远。

#include <iostream>    

template<const char *str> 
struct cts {
    void p() {std::cout << str;}
};

static const char teststr[] = "Hello world!";
int main() {
    cts<teststr> o;
    o.p();
}

http://coliru.stacked-crooked.com/a/64cd254136dd0272

You can have a const char* non-type template parameter, and pass it a const char[] variable with static linkage, which is not all that far from passing a string literal directly.

#include <iostream>    

template<const char *str> 
struct cts {
    void p() {std::cout << str;}
};

static const char teststr[] = "Hello world!";
int main() {
    cts<teststr> o;
    o.p();
}

http://coliru.stacked-crooked.com/a/64cd254136dd0272

风透绣罗衣 2024-08-23 23:49:35

进一步从尼尔的答案来看:根据需要将字符串与模板一起使用的一种方法是定义一个特征类并将字符串定义为该类型的特征。

#include <iostream>

template <class T>
struct MyTypeTraits
{
   static const char* name;
};

template <class T>
const char* MyTypeTraits<T>::name = "Hello";

template <>
struct MyTypeTraits<int>
{
   static const char* name;
};

const char* MyTypeTraits<int>::name = "Hello int";

template <class T>
class MyTemplateClass
{
    public:
     void print() {
         std::cout << "My name is: " << MyTypeTraits<T>::name << std::endl;
     }
};

int main()
{
     MyTemplateClass<int>().print();
     MyTemplateClass<char>().print();
}

印刷

My name is: Hello int
My name is: Hello

Further from Neil's answer: one way to using strings with templates as you want is to define a traits class and define the string as a trait of the type.

#include <iostream>

template <class T>
struct MyTypeTraits
{
   static const char* name;
};

template <class T>
const char* MyTypeTraits<T>::name = "Hello";

template <>
struct MyTypeTraits<int>
{
   static const char* name;
};

const char* MyTypeTraits<int>::name = "Hello int";

template <class T>
class MyTemplateClass
{
    public:
     void print() {
         std::cout << "My name is: " << MyTypeTraits<T>::name << std::endl;
     }
};

int main()
{
     MyTemplateClass<int>().print();
     MyTemplateClass<char>().print();
}

prints

My name is: Hello int
My name is: Hello
二智少女猫性小仙女 2024-08-23 23:49:35

C++20 fixed_string +“非类型模板参数中的类类型”

显然,对此的提案首先被接受,但随后被删除:"字符串文字作为非类型模板参数"

删除是部分原因是因为它被认为很容易处理另一个被接受的提案:“非类型模板参数中的类类型”

已接受的提案包含一个具有以下语法的示例:

template <std::basic_fixed_string Str>
struct A {};
using hello_A = A<"hello">;

我将尝试使用一个示例来更新此示例,一旦我看到支持它的编译器,该示例实际上会告诉我任何信息。

Redditor 还表明以下内容可以在 GCC master 上编译,前提是您定义了自己的 basic_fixed_string 版本,该版本尚未包含在标准库中:https: //godbolt.org/z/L0J2K2

template<unsigned N>
struct FixedString {
    char buf[N + 1]{};
    constexpr FixedString(char const* s) {
        for (unsigned i = 0; i != N; ++i) buf[i] = s[i];
    }
    constexpr operator char const*() const { return buf; }
};
template<unsigned N> FixedString(char const (&)[N]) -> FixedString<N - 1>;

template<FixedString T>
class Foo {
    static constexpr char const* Name = T;
public:
    void hello() const;
};

int main() {
    Foo<"Hello!"> foo;
    foo.hello();
}

g++ -std=c++2a 9.2.1 无法编译该文件:

/tmp/ccZPAqRi.o: In function `main':
main.cpp:(.text+0x1f): undefined reference to `_ZNK3FooIXtl11FixedStringILj6EEtlA7_cLc72ELc101ELc108ELc108ELc111ELc33EEEEE5helloEv'
collect2: error: ld returned 1 exit status

参考书目:https://botondballo.wordpress.com/2018/03/28/trip -report-c-standards-meeting-in-jacksonville-march-2018/

最后,EWG 决定撤回之前批准的允许在非类型模板参数中使用字符串文字的提案,因为允许在非类型模板参数中使用类类型的更通用的设施(刚刚批准)已经足够好了替代品。 (这是与上次会议相比的一个变化,当时我们似乎想要两者兼而有之。)主要区别在于,您现在必须将字符数组包装到一个结构中(想想fixed_string或类似的结构),并将其用作模板参数类型。 (P0424的用户自定义文字部分仍在进行中,对允许的模板参数类型进行了相应的调整。)

这对于 C++17 if constexpr 来说尤其酷:C++编译时的if / else?

这种功能似乎与 C++20 中令人敬畏的“constexpr everything”提案一致,例如: 是否可以在 constexpr 中使用 std::string ?

C++20 fixed_string + "Class Types in Non-Type Template Parameters"

Apparently, a proposal for this was first accepted, but then removed: "String literals as non-type template parameters"

The removal was partly because it was deemed to be easy enough to do with another proposal that was accepted: "Class Types in Non-Type Template Parameters".

The accepted proposal contains an example with the following syntax:

template <std::basic_fixed_string Str>
struct A {};
using hello_A = A<"hello">;

I'll try to update this with an example that actually tells me anything once I see a compiler that supports it.

A Redditor has also shown that the following compiles on GCC master, provided you define your own version of basic_fixed_string which was not in the standard library yet: https://godbolt.org/z/L0J2K2

template<unsigned N>
struct FixedString {
    char buf[N + 1]{};
    constexpr FixedString(char const* s) {
        for (unsigned i = 0; i != N; ++i) buf[i] = s[i];
    }
    constexpr operator char const*() const { return buf; }
};
template<unsigned N> FixedString(char const (&)[N]) -> FixedString<N - 1>;

template<FixedString T>
class Foo {
    static constexpr char const* Name = T;
public:
    void hello() const;
};

int main() {
    Foo<"Hello!"> foo;
    foo.hello();
}

g++ -std=c++2a 9.2.1 from the Ubuntu PPA fails to compile that with:

/tmp/ccZPAqRi.o: In function `main':
main.cpp:(.text+0x1f): undefined reference to `_ZNK3FooIXtl11FixedStringILj6EEtlA7_cLc72ELc101ELc108ELc108ELc111ELc33EEEEE5helloEv'
collect2: error: ld returned 1 exit status

Bibliography: https://botondballo.wordpress.com/2018/03/28/trip-report-c-standards-meeting-in-jacksonville-march-2018/

Finally, EWG decided to pull the previously-approved proposal to allow string literals in non-type template parameters, because the more general facility to allow class types in non-type template parameters (which was just approved) is a good enough replacement. (This is a change from the last meeting, when it seemed like we would want both.) The main difference is that you now have to wrap your character array into a struct (think fixed_string or similar), and use that as your template parameter type. (The user-defined literal part of P0424 is still going forward, with a corresponding adjustment to the allowed template parameter types.)

This will be especially cool with the C++17 if constexpr: if / else at compile time in C++?

This kind of feature appears to be in line with the awesome "constexpr everything" proposals that went into C++20, such as: Is it possible to use std::string in a constexpr?

不爱素颜 2024-08-23 23:49:35

抱歉,C++ 目前不支持使用字符串文字(或实际文字)作为模板参数。

但重新阅读你的问题,这就是你要问的吗?你不能说:

foo <"bar"> x;

但你可以说

template <typename T>
struct foo {
   foo( T t ) {}
};

foo <const char *> f( "bar" );

Sorry, C++ does not currently support the use of string literals (or real literals) as template parameters.

But re-reading your question, is that what you are asking? You cannot say:

foo <"bar"> x;

but you can say

template <typename T>
struct foo {
   foo( T t ) {}
};

foo <const char *> f( "bar" );
子栖 2024-08-23 23:49:35

这是使用 MPLLIBS 将字符串作为模板参数传递的解决方案 (C++11)。

#include <iostream>
#include <mpllibs/metaparse/string.hpp> // https://github.com/sabel83/mpllibs
#include <boost/mpl/string.hpp>

// -std=c++11

template<class a_mpl_string>
struct A
{
  static const char* string;
};

template<class a_mpl_string>
const char* A< a_mpl_string >
::string { boost::mpl::c_str< a_mpl_string >::value };  // boost compatible

typedef A< MPLLIBS_STRING ( "any string as template argument" ) > a_string_type;

int main ( int argc, char **argv )
{
  std::cout << a_string_type{}.string << std::endl;
  return 0;
}

打印:

any string as template argument

github 上的库: https://github.com/sabel83/mpllibs

This is a solution with MPLLIBS to pass a strings as template arguments ( C++11 ).

#include <iostream>
#include <mpllibs/metaparse/string.hpp> // https://github.com/sabel83/mpllibs
#include <boost/mpl/string.hpp>

// -std=c++11

template<class a_mpl_string>
struct A
{
  static const char* string;
};

template<class a_mpl_string>
const char* A< a_mpl_string >
::string { boost::mpl::c_str< a_mpl_string >::value };  // boost compatible

typedef A< MPLLIBS_STRING ( "any string as template argument" ) > a_string_type;

int main ( int argc, char **argv )
{
  std::cout << a_string_type{}.string << std::endl;
  return 0;
}

prints:

any string as template argument

The lib on github: https://github.com/sabel83/mpllibs

无畏 2024-08-23 23:49:35
inline const wchar_t *GetTheStringYouWant() { return L"The String You Want"; }

template <const wchar_t *GetLiteralFunc(void)>
class MyType
{
     void test()
     {
           std::cout << GetLiteralFunc;
     }    
}

int main()
{
     MyType<GetTheStringYouWant>.test();
}

尝试将函数的地址作为模板参数传递。

inline const wchar_t *GetTheStringYouWant() { return L"The String You Want"; }

template <const wchar_t *GetLiteralFunc(void)>
class MyType
{
     void test()
     {
           std::cout << GetLiteralFunc;
     }    
}

int main()
{
     MyType<GetTheStringYouWant>.test();
}

Try it with pasing the address of a function as the template argument.

小红帽 2024-08-23 23:49:35

编辑:好的,你的问题的标题似乎有误导性

“我想要一个在其构造函数中采用两个参数的类。第一个可以是 int、double 或 float,所以,第二个始终是字符串文字“我的字符串”,所以我猜 const char * const ”

看起来您正在尝试实现:

template<typename T>
class Foo
{
  public:
  Foo(T t,  const char* s) : first(t), second(s)
  {
    // do something
  }

  private:
  T first;
  const char* second;

};

这适用于任何类型,对于第一个参数: intfloatdouble 等等。

现在,如果您确实想将第一个参数的类型限制为仅 intfloatdouble;你可以想出一些更复杂的东西,比如

template<typename T>
struct RestrictType;

template<>
struct RestrictType<int>
{
  typedef int Type;
};

template<>
struct RestrictType<float>
{
  typedef float Type;
};

template<>
struct RestrictType<double>
{
  typedef double Type;
};

template<typename T>
class Foo
{
  typedef typename RestrictType<T>::Type FirstType;

  public:
  Foo(FirstType t,  const char* s) : first(t), second(s)
  {
    // do something
  }

  private:
  FirstType first;
  const char* second;

};

int main()
{
  Foo<int> f1(0, "can");
  Foo<float> f2(1, "i");
  Foo<double> f3(1, "have");
  //Foo<char> f4(0, "a pony?");
}

如果你删除最后一行的注释,你将有效地得到一个编译器错误。


不允许使用字符串文字

C++2003 ISO/IEC 14882-2003 §14.1

14.1 模板参数

非类型模板参数应具有以下类型之一(可选 cv 限定):

——整型或枚举类型,

——指向对象的指针或指向函数的指针,

——对对象的引用或对函数的引用,

——指向成员的指针。

ISO/IEC 14882-2003 §14.3.2:

14.3.2 模板非类型参数

非类型、非模板模板参数的模板参数应为以下之一:

——整型或枚举类型的整型常量表达式;或

——非类型模板参数的名称;或

——具有外部链接的对象或函数的地址,包括函数模板和函数模板ID,但不包括非静态类成员,表示为& id 表达式,其中 &如果名称引用函数或数组,或者相应的模板参数是引用,则为可选;或

——指向成员的指针,如 5.3.1 中所述表示。

[注意:字符串文字 (2.13.4) 不满足任何这些类别的要求,因此不是可接受的模板参数。

[示例:

template<class T, char* p> class X { 
  //... 
  X(); 
  X(const char* q) { /* ... */ } 
}; 

X<int,"Studebaker"> x1; //error: string literal as template-argument 
char p[] = "Vivisectionist"; 
X<int,p> x2; //OK 

—结束示例]—结束注释]

看起来它在即将推出的 C++0X 中不会改变,请参阅当前草案 14.4.2 模板非类型参数

EDIT: ok the title of your question seems to be misleading

"I want a class which takes two parameters in its constructor. The first can be either an int, double or float, so , and the second is always a string literal "my string", so I guess const char * const."

It looks like you're trying to achieve:

template<typename T>
class Foo
{
  public:
  Foo(T t,  const char* s) : first(t), second(s)
  {
    // do something
  }

  private:
  T first;
  const char* second;

};

This would work for any type, for the first parameter: int, float, double, whatever.

Now if you really want to restrict the type of the first parameter to be only int, float or double; you can come up with something more elaborate like

template<typename T>
struct RestrictType;

template<>
struct RestrictType<int>
{
  typedef int Type;
};

template<>
struct RestrictType<float>
{
  typedef float Type;
};

template<>
struct RestrictType<double>
{
  typedef double Type;
};

template<typename T>
class Foo
{
  typedef typename RestrictType<T>::Type FirstType;

  public:
  Foo(FirstType t,  const char* s) : first(t), second(s)
  {
    // do something
  }

  private:
  FirstType first;
  const char* second;

};

int main()
{
  Foo<int> f1(0, "can");
  Foo<float> f2(1, "i");
  Foo<double> f3(1, "have");
  //Foo<char> f4(0, "a pony?");
}

If you remove the comment on the last line, you'll effectively get a compiler error.


String literals are not allowed by C++2003

ISO/IEC 14882-2003 §14.1:

14.1 Template parameters

A non-type template-parameter shall have one of the following (optionallycv-qualified) types:

— integral or enumeration type,

— pointer to object or pointer to function,

— reference to object or reference to function,

— pointer to member.

ISO/IEC 14882-2003 §14.3.2:

14.3.2 Template non-type arguments

A template-argument for a non-type, non-template template-parameter shall be one of:

— an integral constant-expression of integral or enumeration type; or

— the name of a non-type template-parameter; or

— the address of an object or function with external linkage, including function templates and function template-ids but excluding non-static class members, expressed as & id expression where the & is optional if the name refers to a function or array, or if the corresponding template-parameter is a reference; or

— a pointer to member expressed as described in 5.3.1.

[Note:A string literal (2.13.4) does not satisfy the requirements of any of these categories and thus is not an acceptable template-argument.

[Example:

template<class T, char* p> class X { 
  //... 
  X(); 
  X(const char* q) { /* ... */ } 
}; 

X<int,"Studebaker"> x1; //error: string literal as template-argument 
char p[] = "Vivisectionist"; 
X<int,p> x2; //OK 

—end example] —end note]

And it looks like it's not going to change in the upcoming C++0X, see the current draft 14.4.2 Template non-type arguments.

是你 2024-08-23 23:49:35

根据您在尼尔的回答下的评论,另一种可能性如下:

#include <iostream>

static const char* eventNames[] = { "event_A", "event_B" };

enum EventId {
        event_A = 0,
        event_B
};

template <int EventId>
class Event
{
public:
   Event() {
     name_ = eventNames[EventId];
   }
   void print() {
        std::cout << name_ << std::endl;
   }
private:
   const char* name_;
};

int main()
{
        Event<event_A>().print();
        Event<event_B>().print();
}

打印

event_A
event_B

Based on your comments under Niel's answer, another possibility is the following:

#include <iostream>

static const char* eventNames[] = { "event_A", "event_B" };

enum EventId {
        event_A = 0,
        event_B
};

template <int EventId>
class Event
{
public:
   Event() {
     name_ = eventNames[EventId];
   }
   void print() {
        std::cout << name_ << std::endl;
   }
private:
   const char* name_;
};

int main()
{
        Event<event_A>().print();
        Event<event_B>().print();
}

prints

event_A
event_B
一人独醉 2024-08-23 23:49:35

您不能直接将字符串文字作为模板参数传递。

但您可以接近:

template<class MyString = typestring_is("Hello!")>
void MyPrint() {
  puts( MyString::data() );
}

...
// or:
MyPrint<typestring_is("another text")>();
...

您所需要的只是此处的一个小头文件。


替代方案:

  • 定义一个全局 char const * 并将其作为指针传递给模板。 (此处

    缺点:需要模板参数列表之外的附加代码。如果您需要指定字符串文字“inline”,则它不适合。

  • 使用非标准语言扩展。 (此处

    缺点:不保证适用于所有编译器。

  • 使用BOOST_METAPARSE_STRING。 (此处

    缺点:您的代码将依赖于 Boost 库。

  • 使用 char 的可变参数模板参数包,例如 str_t<'T','e','s','t'>

    这就是上述解决方案在幕后为您所做的事情。

You cannot pass a string literal directly as a template parameter.

But you can get close:

template<class MyString = typestring_is("Hello!")>
void MyPrint() {
  puts( MyString::data() );
}

...
// or:
MyPrint<typestring_is("another text")>();
...

All you need is a small header file from here.


Alternatives:

  • Define a global char const * and pass it to the template as pointer. (here)

    Drawback: Requires additional code outside of the template argument list. It is not suitable, if you need to specify the string literal "inline".

  • Use a non-standard language extension. (here)

    Drawback: Not guaranteed to work with all compilers.

  • Use BOOST_METAPARSE_STRING. (here)

    Drawback: Your code will depend on the Boost library.

  • Use a variadic template parameter pack of char, e.g. str_t<'T','e','s','t'>.

    This is what the above solution does for you behind the scenes.

我也只是我 2024-08-23 23:49:35

使用代理 static constexpr const char type_name_str[] = {"type name"}; 将字符串作为模板参数传递。使用 [] 定义字符串很重要。

#include <iostream>

template<typename T, const char* const t_name>
struct TypeName
{
public:

    static constexpr const char* Name()         
    {                                   
        return t_name;
    };                                  

};

static constexpr const char type_name_str[] = {"type name"};

int main() 
{
    std::cout<<TypeName<float, type_name_str>::Name();
    return 0;
}

Use proxy static constexpr const char type_name_str[] = {"type name"}; for passing string as template parameter. Defining string using [] is important.

#include <iostream>

template<typename T, const char* const t_name>
struct TypeName
{
public:

    static constexpr const char* Name()         
    {                                   
        return t_name;
    };                                  

};

static constexpr const char type_name_str[] = {"type name"};

int main() 
{
    std::cout<<TypeName<float, type_name_str>::Name();
    return 0;
}
滴情不沾 2024-08-23 23:49:35

我想要一个在其构造函数中带有两个参数的类。第一个可以是 int、double 或 float,所以 ,第二个始终是字符串文字“my string”

template<typename T>
class demo
{
   T data;
   std::string s;

   public:

   demo(T d,std::string x="my string"):data(d),s(x) //Your constructor
   {
   }
};

我不确定,但这是您想要的吗?

I want a class which takes two parameters in its constructor. The first can be either an int, double or float, so , and the second is always a string literal "my string"

template<typename T>
class demo
{
   T data;
   std::string s;

   public:

   demo(T d,std::string x="my string"):data(d),s(x) //Your constructor
   {
   }
};

I am not sure but is this something what you want?

情绪少女 2024-08-23 23:49:35

也许不是OP所要求的,但如果你使用boost,你可以创建一个像这样的宏:

#define C_STR(str_) boost::mpl::c_str< BOOST_METAPARSE_STRING(str_) >::value

然后使用如下:

template<const char* str>
structe testit{
};
testit<C_STR("hello")> ti;

Maybe not what the OP is asking, but if you use boost, you can create a macro like this for example:

#define C_STR(str_) boost::mpl::c_str< BOOST_METAPARSE_STRING(str_) >::value

Then use as follows:

template<const char* str>
structe testit{
};
testit<C_STR("hello")> ti;
许久 2024-08-23 23:49:35
template <char... elements>
struct KSym /* : optional_common_base */ {
  // We really only care that we have a unique-type and thus can exploit being a `""_ksym singleton`
  const char z[sizeof...(elements) + 1] = { elements..., '\0' };
  // We can have properties, we don't need anything to be constexpr for Rs
};
template <typename T, T... chars>
auto&& operator""_ksym() { 
  static KSym<chars...> kSym; // Construct the unique singleton (lazily on demand)
  return kSym;
}
static auto ksym_example1 = "a unique string symbol1\n"_ksym.z;
static auto ksym_example2 = "a unique string symbol2\n"_ksym.z;
auto dont_care = []() {
  ::OutputDebugString(ksym_example1);
  ::OutputDebugString("a unique string symbol2\n"_ksym.z);
  assert("a unique string symbol1\n"_ksym.z == ksym_example1);
  assert("a unique string symbol2\n"_ksym.z == ksym_example2);
  return true; 
}();

以上内容适用于我在 Windows 上使用 Clang 11 进行生产。

(已编辑)我现在在 Windows 上的 clang完全这个使用:

// P0424R1: http://www.open-std.org/jtc1/SC22/wg21/docs/papers/2017/p0424r1.pdf
template <char... chars_ta> struct KSymT;
template <typename T, T... chars_ta> // std::move(KSymT<chars_ta...>::s);
auto operator""_ksym()->KSymT<chars_ta...>& { return KSymT<chars_ta...>::s; }
struct KSym {
  virtual void onRegister() {}
  virtual std::string_view zview_get() = 0;
};

template <char... chars_ta>
struct KSymT : KSym {
  inline static KSymT s;
  // We really only care that we have a unique-type and thus can exploit being a `""_ksym singleton`
  inline static constexpr char z[sizeof...(chars_ta) + 1] = { chars_ta..., '\0' };
  inline static constexpr UIntPk n = sizeof...(chars_ta);
  // We can have properties, we don't need anything to be constexpr for Rs
  virtual std::string_view zview_get() { return std::string_view(z); };
  //#KSym-support compare with `Af_CmdArgs`
  inline bool operator==(const Af_CmdArgs& cmd) {
    return (cmd.argl[0] == n && memcmp(cmd.argv[0], z, n) == 0);
  }
};
template <char... elements>
struct KSym /* : optional_common_base */ {
  // We really only care that we have a unique-type and thus can exploit being a `""_ksym singleton`
  const char z[sizeof...(elements) + 1] = { elements..., '\0' };
  // We can have properties, we don't need anything to be constexpr for Rs
};
template <typename T, T... chars>
auto&& operator""_ksym() { 
  static KSym<chars...> kSym; // Construct the unique singleton (lazily on demand)
  return kSym;
}
static auto ksym_example1 = "a unique string symbol1\n"_ksym.z;
static auto ksym_example2 = "a unique string symbol2\n"_ksym.z;
auto dont_care = []() {
  ::OutputDebugString(ksym_example1);
  ::OutputDebugString("a unique string symbol2\n"_ksym.z);
  assert("a unique string symbol1\n"_ksym.z == ksym_example1);
  assert("a unique string symbol2\n"_ksym.z == ksym_example2);
  return true; 
}();

The above is working for me in production using Clang 11 on Windows.

(edited) I now use exactly this in clang on Windows:

// P0424R1: http://www.open-std.org/jtc1/SC22/wg21/docs/papers/2017/p0424r1.pdf
template <char... chars_ta> struct KSymT;
template <typename T, T... chars_ta> // std::move(KSymT<chars_ta...>::s);
auto operator""_ksym()->KSymT<chars_ta...>& { return KSymT<chars_ta...>::s; }
struct KSym {
  virtual void onRegister() {}
  virtual std::string_view zview_get() = 0;
};

template <char... chars_ta>
struct KSymT : KSym {
  inline static KSymT s;
  // We really only care that we have a unique-type and thus can exploit being a `""_ksym singleton`
  inline static constexpr char z[sizeof...(chars_ta) + 1] = { chars_ta..., '\0' };
  inline static constexpr UIntPk n = sizeof...(chars_ta);
  // We can have properties, we don't need anything to be constexpr for Rs
  virtual std::string_view zview_get() { return std::string_view(z); };
  //#KSym-support compare with `Af_CmdArgs`
  inline bool operator==(const Af_CmdArgs& cmd) {
    return (cmd.argl[0] == n && memcmp(cmd.argv[0], z, n) == 0);
  }
};
美人如玉 2024-08-23 23:49:35

我一直在努力解决类似的问题,最后想出了一个简洁的实现,将字符串文字解压到 char... 模板参数包中,并且不使用 GNU 文字运算符模板扩展:

#include <utility>

template <char ...Chars>
struct type_string_t {
    static constexpr const char data[sizeof...(Chars)] = {Chars...};
};

template <char s(std::size_t), std::size_t ...I>
auto type_string_impl(std::index_sequence<I...>) {
    return type_string_t<s(I)...>();
}

#define type_string(s) \
    decltype (type_string_impl<[] -> constexpr (std::size_t i) {return s[i];}> \
        (std::make_index_sequence<sizeof (s)>()))

static_assert (std::is_same<type_string("String_A"),
                            type_string("String_A")>::value);
static_assert (!std::is_same<type_string("String_A"),
                             type_string("String_B")>::value);

一个主要警告:这取决于 C++20 功能(类值作为非类型模板参数;P0732P1907),(截至 2020 年 12 月)仅(部分)在 GCC 9 及更高版本中实现(预处理器功能测试:(__cpp_nontype_template_args >= 201911L) || (__GNUG__ > ;= 9))。然而,由于该功能是标准的,其他编译器赶上只是时间问题。

I was struggling with a similar problem and finally came up with a concise implementation that unpacks the string literal into a char... template parameter pack and without using the GNU literal operator template extension:

#include <utility>

template <char ...Chars>
struct type_string_t {
    static constexpr const char data[sizeof...(Chars)] = {Chars...};
};

template <char s(std::size_t), std::size_t ...I>
auto type_string_impl(std::index_sequence<I...>) {
    return type_string_t<s(I)...>();
}

#define type_string(s) \
    decltype (type_string_impl<[] -> constexpr (std::size_t i) {return s[i];}> \
        (std::make_index_sequence<sizeof (s)>()))

static_assert (std::is_same<type_string("String_A"),
                            type_string("String_A")>::value);
static_assert (!std::is_same<type_string("String_A"),
                             type_string("String_B")>::value);

A major caveat: this depends on a C++20 feature (class values as non-type template arguments; P0732, P1907), which (as of December 2020) is only (partially) implemented in GCC 9 and later (preprocessor feature test: (__cpp_nontype_template_args >= 201911L) || (__GNUG__ >= 9)). However, since the feature is standard, it is only a matter of time before other compilers catch up.

过度放纵 2024-08-23 23:49:35

这是一个解决方案和扩展/示例

我的解决方案扩展了 https://ctrpeach。 io/posts/cpp20-string-literal-template-parameters/

#include <iostream>
#include <algorithm>
#include <string>

template<size_t N>
struct StringLiteral {
    char value[N];
    constexpr StringLiteral(const char(&str)[N]) {
        std::copy_n(str, N, value);
    }
};

template <StringLiteral T>
struct String {
    static constexpr std::string str() {
        return T.value;
    }
};

template <typename... Strings>
struct JoinedString {
    static constexpr std::string str() {
        return (Strings::str() + ...);
    }
};

template <typename Delim, typename String, typename... Strings>
struct DelimJoinedString {
    static constexpr std::string str() {
        if constexpr (sizeof...(Strings))
            return JoinedString<String, Delim, DelimJoinedString<Delim, Strings...>>::str();
        else
            return String::str();
    }
};

int main() {
    // "123"
    using s123 = String<"123">;
    std::cout << s123::str() << "\n";

    // "abc"
    using abc = String<"abc">;
    std::cout << abc::str() << "\n";

    // "abc123abc123"
    using abc123abc123 = JoinedString<abc, s123, abc, s123>;
    std::cout << abc123abc123::str() << "\n";

    // "abc, 123"
    using abccomma123 = DelimJoinedString<String<", ">, abc, s123>;
    std::cout << abccomma123::str() << "\n";

    // "abc, 123, 123, abc"
    using commaabc123123abc = DelimJoinedString<String<", ">, abc, s123, s123, abc>;
    std::cout << commaabc123123abc::str() << "\n";
    return 0;
}

here is a solution and extensions/examples

my solution extends https://ctrpeach.io/posts/cpp20-string-literal-template-parameters/

#include <iostream>
#include <algorithm>
#include <string>

template<size_t N>
struct StringLiteral {
    char value[N];
    constexpr StringLiteral(const char(&str)[N]) {
        std::copy_n(str, N, value);
    }
};

template <StringLiteral T>
struct String {
    static constexpr std::string str() {
        return T.value;
    }
};

template <typename... Strings>
struct JoinedString {
    static constexpr std::string str() {
        return (Strings::str() + ...);
    }
};

template <typename Delim, typename String, typename... Strings>
struct DelimJoinedString {
    static constexpr std::string str() {
        if constexpr (sizeof...(Strings))
            return JoinedString<String, Delim, DelimJoinedString<Delim, Strings...>>::str();
        else
            return String::str();
    }
};

int main() {
    // "123"
    using s123 = String<"123">;
    std::cout << s123::str() << "\n";

    // "abc"
    using abc = String<"abc">;
    std::cout << abc::str() << "\n";

    // "abc123abc123"
    using abc123abc123 = JoinedString<abc, s123, abc, s123>;
    std::cout << abc123abc123::str() << "\n";

    // "abc, 123"
    using abccomma123 = DelimJoinedString<String<", ">, abc, s123>;
    std::cout << abccomma123::str() << "\n";

    // "abc, 123, 123, abc"
    using commaabc123123abc = DelimJoinedString<String<", ">, abc, s123, s123, abc>;
    std::cout << commaabc123123abc::str() << "\n";
    return 0;
}
巴黎夜雨 2024-08-23 23:49:35

我没有看到提到的另一个 C++20 解决方案,但它足够简单并且适合我自己的需求,是使用 constexpr lambda 作为返回字符串的 NTTP:

#include <string_view>

template<auto getStrLambda>
struct MyType {
    static constexpr std::string_view myString{getStrLambda()};
};

int main() {
    using TypeWithString = MyType<[]{return "Hello world!";}>;
    return 0;
}

编译器资源管理器示例 这里

Another C++20 solution I don't see mentioned, but which was sufficiently simple and suitable for my own needs, is to use a constexpr lambda as the NTTP returning the string:

#include <string_view>

template<auto getStrLambda>
struct MyType {
    static constexpr std::string_view myString{getStrLambda()};
};

int main() {
    using TypeWithString = MyType<[]{return "Hello world!";}>;
    return 0;
}

Compiler explorer example here.

雨后彩虹 2024-08-23 23:49:35

字符串文字“我的字符串”,所以我猜 const char * const

实际上,具有 n 个可见字符的字符串文字是 const char[n+1] 类型。

#include <iostream>
#include <typeinfo>

template<class T>
void test(const T& t)
{
    std::cout << typeid(t).name() << std::endl;
}

int main()
{
    test("hello world"); // prints A12_c on my compiler
}

a string literal "my string", so I guess const char * const

Actually, string literals with n visible characters are of type const char[n+1].

#include <iostream>
#include <typeinfo>

template<class T>
void test(const T& t)
{
    std::cout << typeid(t).name() << std::endl;
}

int main()
{
    test("hello world"); // prints A12_c on my compiler
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文