C++模板如果匹配类型else,则调用成员函数引发异常
C++ Template Call member function if matching type else throw exception?
考虑以下类:
class Example {
const void * pValue;
(Example& (*SIndex(const void *,char *)));
(Example& (*NIndex(const void *,unsigned long long *)));
template<class T,typename I> static Example & Index(const T* value,I index)
{ return Example(value->operator[](index)); }
public:
template<class T> Example(const T& value) {
pValue = &value;
SIndex = (Example& (*(const void *,char *)))Index<T,char *>;
NIndex = (Example& (*(const void *,unsigned long long)))Index<T,unsigned long long>;
};
Example& operator[](char * index) { return SIndex(pValue,index); };
Example& operator[](unsigned long long) { return NIndex(pValue,index); };
}
我希望使用SFINAE(替换失败不是错误)(请参阅http://en.wikipedia.org/wiki/Substitution_failure_is_not_an_error),以更改_Index,这样如果类没有匹配的运算符,它将抛出异常,而不是返回新的Example对象。即,对于_Index<T,char *>
将匹配operator[](char *)
或operator[](std::string&)
,因为std::string
可以从char *
构造而_Index<T,unsigned long long>
将匹配任何数字类型,因为可以转换unsigned long long
。
我刚刚在寻找这个问题的解决方案时遇到了SFINAE,很明显,解决方案就在这里,但我不确定如何实现它。
示例(根据要求):这将进行编译,目前输出的是指针值,没有内容,但这是可以修复的,我还禁用了字符串索引选项,因为这会导致编译器错误,无法使用SFINAE。请注意,现实世界应用程序obj1和obj2可能是不同的类型,即。矢量和映射将产生错误,直到SFINAE被添加到代码中以产生异常为止。此外,要打开的"索引路径"在运行时而不是编译时会造成损害。注意:我正在扩展此代码https://github.com/vitaut/format允许类型为{0[4]〔first〕}或{1〔error〕}等的id。由于并非所有对象都支持这些方法,因此当格式字符串请求时,不支持它的对象应该产生运行时异常,也不能产生编译器错误,因为用作参数的任何类型都将传入Arg类,例如,只是显示了我需要修改的更复杂的Arg类的一部分。
#include <iostream>
#include <string>
#include <vector>
#include <map>
using namespace std;
class Example {
void * pValue;
/*Example& (*SIndex)(void*,const char *);*/
Example& (*NIndex)(void*,unsigned int);
template<class T,typename I> static Example& Index(T* obj,I index) {
return *(new Example((*obj)[index])); }
public:
Example(char value) { pValue = &value; }
template<class T> Example(T& value) {
pValue = &value;
/*SIndex = (Example& (*)(void*,const char *))Index<T,const char *>;*/
NIndex = (Example& (*)(void*,unsigned int))Index<T,unsigned int>;
}
/*Example& operator[](const char * index) { return SIndex(pValue,index); }*/
Example& operator[](unsigned int index) { return NIndex(pValue,index); }
void * Get() { return pValue; }
};
int main()
{
vector<Example> Objs;
vector<string> obj1;
vector<string> obj2;
obj1.push_back("Hello ");
obj1.push_back("World");
obj2.push_back("Olleh ");
obj2.push_back("Dlorw");
Objs.push_back(Example(obj1));
Objs.push_back(Example(obj2));
cout << (string *)(Objs[0][0].Get()) << endl;
cout << (string *)(Objs[1][1].Get()) << endl;
cin.ignore();
return 0;
}
示例2(使用Simple的SFINALE代码)v2:
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <utility>
#include <type_traits>
using namespace std;
template<typename T, typename I>
decltype(void((*declval<T>())[declval<I>()]), true_type())
has_subscript_test(int);
template<typename, typename>
false_type
has_subscript_test(...);
template<typename T, typename I>
struct has_subscript : decltype(has_subscript_test<T, I>(0))
{
};
class Example {
void * pValue;
Example& (*SIndex)(void*,const char *);
Example& (*NIndex)(void*,unsigned int);
template<class T,typename I> static
typename enable_if<has_subscript<T, I>::value, Example&>::type
Index(T* obj,I index) { return *(new Example((*obj)[index])); }
template<class T,typename I> static
typename enable_if<!has_subscript<T, I>::value, Example&>::type
Index(T* obj,I index) { throw "Invalid Index Type"; }
public:
//Example(char value) { pValue = &value; }
template<class T> Example(T& value) {
pValue = &value;
SIndex = (Example& (*)(void*,const char *))Index<T,const char *>;
NIndex = (Example& (*)(void*,unsigned int))Index<T,unsigned int>;
}
Example& operator[](const char* index) { return SIndex(pVale,index); }
Example& operator[](unsigned int index) { return NIndex(pValue,index); }
void * Get() { return pValue; }
};
int main()
{
vector<Example> Objs;
vector<string> obj1;
map<string,string> obj2;
obj1.push_back("Hello ");
obj1.push_back("World");
obj2["A"] = "Olleh ";
obj2["B"] = "Dlorw";
Objs.push_back(Example(obj1));
Objs.push_back(Example(obj2));
cout << (string *)(Objs[0][(unsigned int)0].Get()) << endl;
cout << (string *)(Objs[1][(const char *)"B"].Get()) << endl;
cin.ignore();
return 0;
}
编译器错误:看起来只有前两个很重要,其余的都是这两个的副作用。
g++.exe -Wall -fexceptions -std=c++11 -g -c C:/SourceCode/Test/main.cpp -o ../obj/Debug/main.o
cygwin warning:
MS-DOS style path detected: C:/SourceCode/Test/main.cpp
Preferred POSIX equivalent is: /cygdrive/c/SourceCode/Test/main.cpp
CYGWIN environment variable option "nodosfilewarning" turns off this warning.
Consult the user's guide for more details about POSIX paths:
http://cygwin.com/cygwin-ug-net/using.html#using-pathnames
C:/SourceCode/Test/main.cpp: In instantiation of ‘static typename std::enable_if<has_subscript<T, I>::value, Example&>::type Example::Index(T*, I) [with T = std::vector<std::basic_string<char> >; I = const char*; typename std::enable_if<has_subscript<T, I>::value, Example&>::type = Example&]’:
C:/SourceCode/Test/main.cpp:37:9: required from ‘Example::Example(T&) [with T = std::vector<std::basic_string<char> >]’
C:/SourceCode/Test/main.cpp:54:32: required from here
C:/SourceCode/Test/main.cpp:29:64: error: invalid conversion from ‘const char*’ to ‘std::vector<std::basic_string<char> >::size_type {aka unsigned int}’ [-fpermissive]
In file included from /usr/lib/gcc/i686-pc-cygwin/4.7.3/include/c++/vector:65:0,
from C:/SourceCode/Test/main.cpp:3:
/usr/lib/gcc/i686-pc-cygwin/4.7.3/include/c++/bits/stl_vector.h:750:7: error: initializing argument 1 of ‘std::vector<_Tp, _Alloc>::reference std::vector<_Tp, _Alloc>::operator[](std::vector<_Tp, _Alloc>::size_type) [with _Tp = std::basic_string<char>; _Alloc = std::allocator<std::basic_string<char> >; std::vector<_Tp, _Alloc>::reference = std::basic_string<char>&; std::vector<_Tp, _Alloc>::size_type = unsigned int]’ [-fpermissive]
C:/SourceCode/Test/main.cpp: In instantiation of ‘static typename std::enable_if<has_subscript<T, I>::value, Example&>::type Example::Index(T*, I) [with T = std::map<std::basic_string<char>, std::basic_string<char> >; I = unsigned int; typename std::enable_if<has_subscript<T, I>::value, Example&>::type = Example&]’:
C:/SourceCode/Test/main.cpp:38:9: required from ‘Example::Example(T&) [with T = std::map<std::basic_string<char>, std::basic_string<char> >]’
C:/SourceCode/Test/main.cpp:55:32: required from here
C:/SourceCode/Test/main.cpp:29:64: error: invalid user-defined conversion from ‘unsigned int’ to ‘std::map<std::basic_string<char>, std::basic_string<char> >::key_type&& {aka std::basic_string<char>&&}’ [-fpermissive]
In file included from /usr/lib/gcc/i686-pc-cygwin/4.7.3/include/c++/string:54:0,
from /usr/lib/gcc/i686-pc-cygwin/4.7.3/include/c++/bits/locale_classes.h:42,
from /usr/lib/gcc/i686-pc-cygwin/4.7.3/include/c++/bits/ios_base.h:43,
from /usr/lib/gcc/i686-pc-cygwin/4.7.3/include/c++/ios:43,
from /usr/lib/gcc/i686-pc-cygwin/4.7.3/include/c++/ostream:40,
from /usr/lib/gcc/i686-pc-cygwin/4.7.3/include/c++/iostream:40,
from C:/SourceCode/Test/main.cpp:1:
/usr/lib/gcc/i686-pc-cygwin/4.7.3/include/c++/bits/basic_string.h:487:7: note: candidate is: std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _CharT*, const _Alloc&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>] <near match>
/usr/lib/gcc/i686-pc-cygwin/4.7.3/include/c++/bits/basic_string.h:487:7: note: no known conversion for argument 1 from ‘unsigned int’ to ‘const char*’
C:/SourceCode/Test/main.cpp:29:64: error: invalid conversion from ‘unsigned int’ to ‘const char*’ [-fpermissive]
In file included from /usr/lib/gcc/i686-pc-cygwin/4.7.3/include/c++/string:54:0,
from /usr/lib/gcc/i686-pc-cygwin/4.7.3/include/c++/bits/locale_classes.h:42,
from /usr/lib/gcc/i686-pc-cygwin/4.7.3/include/c++/bits/ios_base.h:43,
from /usr/lib/gcc/i686-pc-cygwin/4.7.3/include/c++/ios:43,
from /usr/lib/gcc/i686-pc-cygwin/4.7.3/include/c++/ostream:40,
from /usr/lib/gcc/i686-pc-cygwin/4.7.3/include/c++/iostream:40,
from C:/SourceCode/Test/main.cpp:1:
/usr/lib/gcc/i686-pc-cygwin/4.7.3/include/c++/bits/basic_string.h:487:7: error: initializing argument 1 of ‘std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _CharT*, const _Alloc&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]’ [-fpermissive]
C:/SourceCode/Test/main.cpp:29:64: error: conversion to non-const reference type ‘std::map<std::basic_string<char>, std::basic_string<char> >::key_type&& {aka class std::basic_string<char>&&}’ from rvalue of type ‘std::basic_string<char>’ [-fpermissive]
这应该有效:
template<typename T, typename I>
decltype(void((*std::declval<T>())[std::declval<I>()]), std::true_type())
has_subscript_test(int);
template<typename, typename>
std::false_type
has_subscript_test(...);
template<typename T, typename I>
struct has_subscript : decltype(has_subscript_test<T, I>(0))
{
};
class Example {
const void * pValue;
(Example& (*SIndex(const void *,char *)));
(Example& (*NIndex(const void *,unsigned long long *)));
template<class T, typename I> static
typename std::enable_if<has_subscript<T, I>::value, Example&>::type
_Index(const T* value,I index) { return Example((*value)[index]); }
template<class T, typename I> static
typename std::enable_if<!has_subscript<T, I>::value, Example&>::type
_Index(const T*,I) { throw "uh-oh!"; }
public:
template<class T> Example(const T& value) {
pValue = &value;
SIndex = (Example& (*(const void *,char *)))_Index<T,char *>;
NIndex = (Example& (*(const void *,unsigned long long)))_Index<T,unsigned long long>;
};
Example& operator[](char * index) { return SIndex(this,index); };
Example& operator[](unsigned long long) { return NIndex(this,index); };
};
我已经完成了SFINAE部分,但您的代码还有其他问题。_Index
不允许作为名称,您通过引用返回一个临时的,并且您试图将成员指针强制转换为函数指针(即使使用不同的函数类型!)
- 对RValue对象调用的LValue ref限定成员函数
- 为什么使用 "this" 指针调用派生成员函数?
- 基于另一个成员参数将函数调用从类传递给它的一个成员
- 我不小心调用了一个没有自己类对象的成员函数.但这是怎么回事呢
- 为什么类中的ostringstream类型的成员会导致";调用隐含删除复制构造函数";错误
- 无法为类成员调用函数
- C++ 类成员调用错误 C3861
- 用const_iterator成员调用类destructor时堆积损坏
- C++ 如何为类的所有成员调用方法
- 通过命名成员调用虚拟与地址或引用的区别
- 使用类成员调用函数
- 正在成员调用中实例化类
- 使用父类中的私有成员调用父构造函数
- 带有类 - 非静态成员调用的 typedef 函数声明
- C++:对非静态成员函数指针的成员调用
- 需要从静态成员调用函数(由静态指针引用)
- 用类成员调用构造函数,c++
- 将luabind派生成员调用为协同程序
- 为什么我没有得到编译错误时,我从const方法内部的ref成员调用非const方法
- 类成员函数正常工作,但当作为另一个类的数据成员调用时陷入无限循环