C++ 将 const char* 作为模板参数传递

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3773378/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 13:40:42  来源:igfitidea点击:

Passing const char* as template argument

c++stringtemplates

提问by Puppy

Why can't you pass literal strings in here? I made it work with a very slight workaround.

为什么不能在这里传递文字字符串?我用一个非常小的解决方法让它工作。

template<const char* ptr> struct lols {
    lols() : i(ptr) {}
    std::string i;
};
class file {
public:
    static const char arg[];
};
decltype(file::arg) file::arg = __FILE__;
// Getting the right type declaration for this was irritating, so I C++0xed it.

int main() {
    // lols<__FILE__> hi; 
    // Error: A template argument may not reference a non-external entity
    lols<file::arg> hi; // Perfectly legal
    std::cout << hi.i;
    std::cin.ignore();
    std::cin.get();
}

采纳答案by Johannes Schaub - litb

Because this would not be a useful utility. Since they are not of the allowed form of a template argument, it currently does not work.

因为这不是一个有用的实用程序。由于它们不是模板参数的允许形式,因此目前不起作用。

Let's assume they work. Because they are not required to have the same address for the same value used, you will get different instantiations even though you have the same string literal value in your code.

让我们假设它们有效。因为对于所使用的相同值,它们不需要具有相同的地址,所以即使您的代码中具有相同的字符串文字值,您也会获得不同的实例化。

lols<"A"> n;

// might fail because a different object address is passed as argument!
lols<"A"> n1 = n;

You could write a plugin for your text editor that replaces a string by a comma separated list of character literals and back. With variadic templates, you could "solve" that problem this way, in some way.

您可以为文本编辑器编写一个插件,用逗号分隔的字符文字列表替换字符串并返回。使用可变参数模板,您可以以某种方式“解决”这个问题。

回答by Nathan Ernst

It is possible, but the the template argument must have external linkage, which precludes using literal strings and mitigates the utility of doing this.

这是可能的,但模板参数必须具有外部链接,这会阻止使用文字字符串并降低这样做的效用。

An example I have is:

我的一个例子是:

template<const char* name, const char* def_value=empty_>
struct env : public std::string
{
    env()
    {
        const char* p = std::getenv(name);
        assign(p ? p : def_value);
    }
};

extern const char empty_[] = "";

std::string test = env<empty_>();

回答by Michael

This is how I do it. Makes a lot more sense to me:

我就是这样做的。对我来说更有意义:

struct MyString { static const std::string val; }
const std::string MyString::val = "this is your string";

template<typename T>
void func()
{
  std::cout << T::val << std::endl;
}

void main()
{
  func<MyString>();
}

回答by Ben Earhart

This works for classes and, IMO, is useful. The implementation is quick and dirty but can easily be made cleaner:

这适用于课程,并且在 IMO 中很有用。实现既快速又脏,但可以很容易地变得更干净:

#include <stdio.h>
#include <string.h>

struct TextTag { const char *text; };

template <const TextTag &TRUE, const TextTag &FALSE>
struct TextTaggedBool
{
  const char *GetAsText() const { return m_value ? TRUE.text: FALSE.text; }
  void SetByText(const char *s) { m_value = !strcmp(s, TRUE.text); }
  bool m_value;
};

class Foo
{
public:
    void method()
    {
        m_tbool.SetByText("True!");  printf("%s\n", m_tbool.GetAsText());
        m_tbool.SetByText("False!"); printf("%s\n", m_tbool.GetAsText());
        m_tbool.m_value = true;  printf("%s\n", m_tbool.GetAsText());
        m_tbool.m_value = false; printf("%s\n", m_tbool.GetAsText());
    }

private:
    static constexpr TextTag TrueTag = { "True!" };
    static constexpr TextTag FalseTag = { "False!" };
    TextTaggedBool<TrueTag, FalseTag> m_tbool;
};

void main() { Foo().method(); }

Output:

输出:

True! False! True! False!

真的!错误的!真的!错误的!

回答by Nathan Chappell

Good question, thought I'd throw my hat into the ring... I guess you can pass pointers to static variables as non-type template arguments. From C++20 it looks like it won't be an issue... Until then, here is some cheap macro to make it work.

好问题,我想我会把我的帽子扔进戒指......我猜你可以将指向静态变量的指针作为非类型模板参数传递。从 C++20 看起来它不会成为问题......在那之前,这里有一些便宜的宏可以让它工作。

template <const char *Name, typename T>
struct TaggedValue {
  static constexpr char const *name{Name};
  T value;
  friend ostream &operator<<(ostream &o, const TaggedValue &a) {
    return o << a.name << " = " << a.value;
  }
};

#define ST(name, type)\
  const char ST_name_##name[]{#name};\
  using name = TaggedValue<ST_name_##name,type>;

ST(Foo, int);
ST(Bar, int);
ST(Bax, string);

int main() {
  cout << Foo{3} << endl;
  cout << Bar{5} << endl;
  cout << Bax{"somthing"} << endl;
}