2017-06-22 31 views
0

对于a similar SO question我想出了以下解决方案:限制传递的参数的非暂时性的字符串字面

#include <cstdlib> 

class Literal 
{ 
    public: 

    template <std::size_t N> constexpr 
    Literal(const char (&str)[N]) 
    : mStr(str), 
     mLength(checkForTrailingZeroAndGetLength(str[N - 1], N)) 
    { 
    } 

    template <std::size_t N> Literal(char (&str)[N]) = delete; 

    constexpr operator const char*() const noexcept 
    { 
     return mStr; 
    } 

    constexpr const char* c_str() const noexcept 
    { 
     return mStr; 
    } 

    private: 
    const char* mStr; 
    std::size_t mLength; 

    struct Not_a_CString_Exception{}; 

    constexpr static 
    std::size_t checkForTrailingZeroAndGetLength(char ch, std::size_t sz) 
    { 
     return (ch) ? throw Not_a_CString_Exception() : (sz - 1); 
    } 
}; 

它非常好,但它仍然有可能要创建从自动存储时间阵列一个文字。我希望在编译时避免这种情况。下面的例子是未定义行为:

#include <cstdio> 

static Literal okay() 
{ 
    static constexpr const char okay[] = "okay"; 
    return { okay }; 
} 

static Literal boom() 
{ 
    const char boom[] = "boom"; //Oops, static forgotten 
    return { boom }; // <= How to force a compile error here? 
} 

int main() 
{ 
    printf("%s\n", okay().c_str()); // <= the intended use case 
    printf("%s\n", boom().c_str()); // <= the undefined behaviour 
    return 0; 
} 

它也可以在godbolt compiler explorer找到。是否有可能在编译时检测到这个用例并强制编译错误?

+0

你为什么不坚持使用该文本操作方式 – Sopel

+0

其实我们使用的文字有一段时间了,从来没有绊倒在这个陷阱,因为我们的开发人员通常采取的字面操作方式。另一方面,如果一个开发人员出于任何原因编写这样的构造,我宁愿在编译时捕获它,而不是无尽的调试会话。 –

+1

听起来你应该只是使应用构造函数的私人和文本操作模板的朋友。 –

回答

0

不,这是不可能的。 okay,boom,以及相同大小的字符串文字都具有相同的类型,并且与表达式无法区分。